与不同模型关系中的双向行为
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)
我有一些 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)