在Pony ORM中是否可以在多对多关系的中间表中添加额外的属性?

equ*_*ghe 4 attributes many-to-many ponyorm

在Pony ORM中,可以"自动"创建多对多关系.例如,从文档(对于版本0.6,强调我的):

要创建多对多关系,您需要将关系的两端定义为Set属性:

class Product(db.Entity):
    tags = Set("Tag")

class Tag(db.Entity):
    products = Set(Product)
Run Code Online (Sandbox Code Playgroud)

为了在数据库中实现这种关系,Pony将创建一个中间表.这是一个众所周知的解决方案,它允许您在关系数据库中拥有多对多关系.

是否可以在自动创建的中间表中创建额外的属性(列),因此不仅仅是"产品"和"标签"的外键,还有例如时间戳?

如果有,怎么样?

如果没有,我想我必须明确地创建中间表.在这种情况下,我仍然可以使用nice Set-attribute定义(可能是中间表,指示感兴趣的属性)?

Ale*_*sky 8

目前有必要定义显式实体,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

Pony不支持Django中的虚拟Set属性through,但我们计划在将来添加它们.现在你需要明确地使用中间表.

将标签添加到产品中

p1 = Product[1]
tag1 = Tag.get(name='smartphones')

p1.tags.create(tag=tag1)
# or:
ProductTag(product=p1, tag=tag1)
Run Code Online (Sandbox Code Playgroud)

从产品中删除标记:

ProductTag[p1, tag1].delete()
Run Code Online (Sandbox Code Playgroud)

检查产品是否具有特定标签:

ProductTag.get(product=p1, tag=tag1) is not None
Run Code Online (Sandbox Code Playgroud)

此外,Pony支持属性提升的概念.这意味着在Pony中,任何集合属性都具有其项目的所有属性.此类集合属性的值是各个项的所有值的集合.例如,为了获取特定产品的所有标签,您可以编写:

p1.tags.tag
Run Code Online (Sandbox Code Playgroud)

p1.tags表达式返回的集合ProductTag项目.每个ProductTag对象都具有tag指向特定标记对象的属性.因此p1.tags.tag返回Tag与特定Product对象链接的所有对象的集合.

可以在查询中使用属性提升.例如,为了找到带有标记的所有产品,smartphones您可以编写以下查询:

select(p for p in Product if 'smartphones' in p.tags.tag.name)
Run Code Online (Sandbox Code Playgroud)

这里p.tagsProductTag对象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))
Run Code Online (Sandbox Code Playgroud)

此外,查询可以重写为:

select(pt.product for pt in ProductTag if pt.tag.name == 'smartphones')
Run Code Online (Sandbox Code Playgroud)