7

在 Pony ORM 中,可以“自动”创建多对多关系。例如,来自文档(对于 0.6 版,强调我的):

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

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

class Tag(db.Entity):
    products = Set(Product)

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

是否可以在自动创建的中间表中创建一个额外的属性(列),所以不仅仅是“产品”和“标签”的外键,还有时间戳?

如果是,如何?

如果没有,我想我将不得不显式地创建中间表。在那种情况下,我是否仍然可以使用 nice Set-attribute 定义(可能是中间表,指示感兴趣的属性)?

4

1 回答 1

12

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

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 支持属性提升的概念。这意味着在 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.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))

此外,查询可以重写为:

select(pt.product for pt in ProductTag if pt.tag.name == 'smartphones')
于 2016-02-15T16:32:20.773 回答