[英]Access parent object from sqlalchemy association_proxy creator
[英]Update a sqlalchemy association proxy target when updating the parent ORM table
我有一个 Flask SQLAlchemy 项目,其中包含 3 个 ORM 表、Category、Vendor 和 CategoryVendorMap,我正在使用 Flask-Marshmallow 为 api 定义模式。
关系:通过 CategoryVendorMap,Category 有很多 Vendor。 CategoryVendorMap 也有一个is_default
标志,指示类别的默认供应商。 此is_default
字段也已非规范化到 Category 表中。
有没有办法通过只访问Category
ORM Mapper 来设置CategoryVendorMap
对象的is_default
值? 基本上我想设置Category.default_vendor_id
字段并让这个字段的设置器更新适当的CategoryVendorMap
关联。我知道我可以直接更新CategoryVendorMap
对象,但是最终我的模型是通过 api 公开的,我想避免暴露这个对象,并创建自定义控制器逻辑来处理这个用例。
class CategoryVendorMap(db.Model):
__tablename__ = "CategoryVendorMap"
__table_args__ = (
db.PrimaryKeyConstraint('category_id', 'vendor_id'),
)
category_id = db.Column(db.Integer, db.ForeignKey('Category.category_id'))
vendor_id = db.Column(db.Integer, db.ForeignKey('Vendor.vendor_id'))
is_default = db.Column(db.Boolean, default=False)
category = db.relationship('Category', backref=db.backref("category_vendors", cascade="all, delete-orphan"))
vendor = db.relationship('Vendor')
class Category(db.Model):
__tablename__ = 'Category'
@property
def default_vendor_id(self):
if self.category_vendors:
default_vendor_id = [cat_vendor_map for cat_vendor_map in self.category_vendors if cat_vendor_map.is_default]
return default_vendor_id[0].vendor_id if default_vendor_id else None
return
@default_vendor_id.setter
def default_vendor_id(self, vendor_id):
return int(vendor_id)
category_id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), unique=False, nullable=False)
vendors = association_proxy("category_vendors", "vendor",
creator=lambda vendor: CategoryVendorMap(vendor=vendor))
class Vendor(db.Model):
__tablename__ = 'Vendor'
vendor_id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, nullable=False)
您可以尝试使用混合属性并在.setter
使用自定义逻辑:
@hybrid_property
def default_vendor_id(self):
res = [_cv for _cv in self.category_vendors if _cv.is_default]
return res and res[0].vendor_id or None
@default_vendor_id.setter
def default_vendor_id(self, value):
# @note: need thorough testing in case a new vendor is added and set to be a default
# also new objects will not have the `vendor_id` set yet
for _cv in self.category_vendors:
_cv.is_default = bool(_cv.vendor_id == value)
但是,需要很好地测试 setter 以涵盖极端情况,其中一些在评论中提到。
您还可以考虑在CategoryVendorMap
表上创建检查约束(或唯一过滤索引),以确保每个类别最多只有一个is_default
真值。
另一个要考虑的选择是将is_default
标志从关系表中直接移动到Category
模型。 在这种情况下,当然,您必须验证默认供应商是现有供应商之一。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.