Возможно ли в Pony ORM добавить дополнительные атрибуты в промежуточную таблицу отношения "многие ко многим"?
В Pony ORM возможно "автоматически" создать отношение "многие ко многим". Например, из документации (для версии 0.6, выделено мое):
Чтобы создать отношение "многие ко многим", необходимо определить оба конца отношения как "Задать атрибуты":
class Product(db.Entity): tags = Set("Tag") class Tag(db.Entity): products = Set(Product)
Чтобы реализовать эту связь в базе данных, Пони создаст промежуточную таблицу. Это хорошо известное решение, которое позволяет вам иметь отношения "многие ко многим" в реляционных базах данных.
Можно ли создать дополнительный атрибут (столбец) в автоматически создаваемой промежуточной таблице, чтобы не только внешние ключи для "Product" и "Tag", но, например, также временная метка?
Если да, то как?
Если нет, я думаю, мне придется явно создать промежуточную таблицу. Могу ли я в этом случае использовать хороший Set
определение атрибута (возможно, к промежуточной таблице с указанием атрибута интереса)?
1 ответ
В настоящее время необходимо определить явную сущность, например:
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)
Пони не поддерживает виртуальные 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.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')