在Pony ORM中,可以“自动”创建多对多关系。例如,from the documentation(对于版本0.6,强调我的):
为了创建多对多关系,您需要定义两者 设置属性的关系结束:
class Product(db.Entity): tags = Set("Tag") class Tag(db.Entity): products = Set(Product)
为了在数据库中实现这种关系,Pony会 创建中间表。这是众所周知的解决方案 允许您在关系数据库中拥有多对多关系。
是否可以在自动创建的中间表中创建额外的属性(列),因此不仅仅是“产品”和“标记”的外键,还有例如时间戳?
如果是,怎么样?
如果没有,我想我必须明确地创建中间表。在这种情况下,我是否仍然可以使用漂亮的Set
- 属性定义(可能是中间表,表示感兴趣的属性)?
答案 0 :(得分:7)
目前有必要定义显式实体,如下所示:
class Product(db.Entity):
name = Required(str)
tags = Set("ProductTag")
class Tag(db.Entity):
name = Required(str, unique=True)
products = Set("ProductTag")
class ProductTag(db.Entity):
product = Required(Product)
tag = Required(Tag)
PrimaryKey(product, tag)
timestamp = Required(datetime, default=datetime.now)
Pony不支持Django中的Set
等虚拟through
属性,但我们计划将来添加它们。现在你需要明确地使用中间表。
向产品添加标记
p1 = Product[1]
tag1 = Tag.get(name='smartphones')
p1.tags.create(tag=tag1)
# or:
ProductTag(product=p1, tag=tag1)
从产品中删除代码:
ProductTag[p1, tag1].delete()
检查产品是否有特定标签:
ProductTag.get(product=p1, tag=tag1) is not None
此外,Pony支持attribute lifting的概念。这意味着在Pony中,任何集合属性都具有其项目的所有属性。此类集合属性的值是各个项的所有值的集合。例如,为了获取特定产品的所有标签,您可以写:
p1.tags.tag
p1.tags
表达式返回ProductTag
项的集合。每个ProductTag
对象都有tag
属性,该属性指向特定的标记对象。因此,p1.tags.tag
会返回与特定Tag
对象关联的所有Product
个对象的集合。
可以在查询中使用属性提升。例如,为了找到标记为smartphones
的所有产品,您可以编写以下查询:
select(p for p in Product if 'smartphones' in p.tags.tag.name)
此处,p.tags
是ProductTag
个对象的集合,p.tags.tag
是Tag
个对象的集合,p.tags.tag.name
是标记名称的集合。上面的查询是以下查询的语法糖:
select(p for p in Product if 'smartphones' in select(item.tag.name for item in p.tags))
此外,查询可以重写为:
select(pt.product for pt in ProductTag if pt.tag.name == 'smartphones')