与不同模型关系中的双向行为

Bidirectional behavior in relationships to different models

我有一些 classess 具有不同的属性(请求),所有这些都应该与另一个 class(通知)

我的结构是这样的:

db = SQLAlchemy()

class RequestMixin(object):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    description = db.Column(db.Text(250))

    @declared_attr
        def __tablename__(self):
        return self.__name__.lower()

    @declared_attr
    def notification_id(self):
        return db.Column(db.Integer, ForeignKey('notification.id'))

    @declared_attr
    def notification(self):
        return db.relationship('Notification')

def DailyLeaveRequest(db.Model, RequestMixin):
    demand_date = db.Column(db.Date, nullable=False)

def HourlyLeaveRequest(db.Model, RequestMixin):
    demand_date = db.Column(db.Date, nullable=False)
    time_from = db.Column(db.String(10), nullable=False)
    time_to = db.Column(db.String(10), nullable=False)

def FundRequest(db.Model, RequestMixin):
    amount = db.Column(db.Integer)


class Notification(db.Model):
    __tablename__='notification'
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    seen = db.Column(db.BOOLEAN, nullable=False, default=False)
    concept = db.Column(db.Integer, nullable=False)
    # and some relationships to users which doesn't matter here

这样我就可以通过每个Request对象访问到Notification对象,但是因为没有'backref',我不能反过来访问。

所以我现在做的是检查Notification.concept并手动查询相关请求。这样:

if notification_obj.concept == 1:
    related_request = DailyLeaveRequest.query.filter_by(notification_id=notification_obj.id).first()
elif notification_obj == 2:
    .
    .

真恶心。 (我有超过 3 个请求 classes)

当我尝试添加这样的反向引用时:

.
.
@declared_attr
def notification(self):
    return db.relationship('Notification', backref='request')
.
.

,我得到这个错误:

sqlalchemy.exc.ArgumentError: Error creating backref 'request' on relationship 'HourlyLeaveRequest.notification': property of that name exists on mapper 'Mapper|Notification|notification'

有没有办法让 class 与其他具有反向访问权限的不同 class 相关?

你应该看看SQLAlchemy's polymorphic relationships

最简单的使用方法是 joined table inheritance。它允许您定义具有所有公共属性的基础 table,包括与 Notification.

的关系
class Request(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    description = db.Column(db.Text(250))

    notification_id = db.Column(db.Integer, ForeignKey('notification.id'))
    notification = db.relationship('Notification')

    type = db.Column(db.String(50))

    __mapper_args__ = {
        'polymorphic_identity': 'request',
        'polymorphic_on': type,
    }


class DailyLeaveRequest(Request):
    id = db.Column(db.Integer, db.ForeignKey('request.id'), primary_key=True)

    demand_date = db.Column(db.Date, nullable=False)

    __mapper_args__ = {
        'polymorphic_identity': 'dailyleave',
    }


class HourlyLeaveRequest(Request):
    id = db.Column(db.Integer, db.ForeignKey('request.id'), primary_key=True)

    demand_date = db.Column(db.Date, nullable=False)
    time_from = db.Column(db.String(10), nullable=False)
    time_to = db.Column(db.String(10), nullable=False)

    __mapper_args__ = {
        'polymorphic_identity': 'hourlyleave',
    }


def FundRequest(Request):
    id = db.Column(db.Integer, db.ForeignKey('request.id'), primary_key=True)

    amount = db.Column(db.Integer)

    __mapper_args__ = {
        'polymorphic_identity': 'hourlyleave',
    }

然后您可以查询所有 Requests:

requests = Request.query.all()
for request in requests:
    demand_date = getattr(
        request, 'demand_date', 'demand_date not available on this type')
    print(request.type, demand_date)

Request 和特定 table 的所有属性都可用,但其他 table 的属性不可用。

您还可以查询特定类型:

requests = DailyLeaveRequest.query.all():
for request in requests:
    print(request.type, request.demand_date)