#python #sqlalchemy
#python #sqlalchemy
Вопрос:
У меня простая структура данных, где таблица film имеет внешний ключ к таблице country.
Чтобы получить все фильмы из одной страны, у меня есть это свойство ‘same_country_films’, самореферентная связь.
Оно почти выполняет свою работу правильно, однако оно также включает сам фильм в список. Как я могу исключить это и просто иметь другие фильмы?
Большое спасибо!
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.orm import mapper, relationship
metadata = MetaData()
country_table = Table('country', metadata,
Column('id', String, primary_key=True),
Column('name', String),
)
film_table = Table('film', metadata,
Column('id', Integer, primary_key=True),
Column('title', String),
Column('year', Integer),
Column('country_id', Integer, ForeignKey('country.id'))
)
class Country(object):
pass
class Film(object):
pass
mapper(Country, country_table)
mapper(Film, film_table,
properties={
'country':relationship(
Country,
backref='films'),
'same_country_films':relationship(
Film,
primaryjoin=film_table.c.country_id==
film_table.c.country_id,
foreign_keys=[
film_table.c.country_id,
]
)
}
)
Ответ №1:
Самое простое решение — самостоятельно закодировать это свойство вместо отношения:
class Film(object):
@property
def same_country_films(self):
return [f for f in self.country.films if f!=self]
Это решение не будет выполнять отдельный запрос для этого свойства, когда оба film.same_country_films
и country.films
доступны во время сеанса. Свойство не может быть обновлено, как вы обычно можете сделать с relation, но я сомневаюсь, что это действительно необходимо.
Плохо то, что оно оценивается для каждого доступа (не так много работы). Вы можете изменить property
декоратор на chaching (как cached_property
в werkzeug), но тогда свойство не будет отражать изменения в country.films
после первого доступа к нему.
Комментарии:
1. Спасибо за ответ. Это хорошее решение представленной проблемы. Честно говоря, моя настоящая цель — использовать этот пример со страной фильма, чтобы исследовать, как работают отношения. Возможно ли вообще решить проблему с использованием отношения?
Ответ №2:
Я думаю, это должно сработать (хотя я на самом деле не тестировал это):
primaryjoin=sqlalchemy.and_(
film_table.c.country_id==film_table.c.country_id,
film_table.c.id!=film_table.c.id)
Комментарии:
1. Не совсем. Оно не заменяет film_table.c.id с помощью? в сгенерированном sql.