Самореферентные отношения sqlalchemy, не включая «я»

У меня есть простая структура данных, где таблица фильмов имеет внешний ключ для таблицы стран.

Чтобы получить все фильмы из одной и той же страны, у меня есть свойство '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,
                        ]
                    )
             }
    )

person Xuan    schedule 14.04.2011    source источник


Ответы (2)


Самое простое решение — закодировать это свойство самостоятельно вместо отношения:

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. Свойство нельзя обновить, как обычно можно сделать с отношением, но я сомневаюсь, что это действительно необходимо.

Плохо то, что он оценивается для каждого доступа (не так много работы). Вы можете изменить декоратор property на chaching (например, cached_property в werkzeug), но тогда свойство не будет отражать изменения в country.films после первого доступа к нему.

person Denis Otkidach    schedule 21.04.2011
comment
Спасибо за ответ. Это хорошее решение представленной проблемы. Честно говоря, моя настоящая цель — использовать этот пример страны кино, чтобы исследовать, как работают отношения. Можно ли вообще решить проблему с помощью отношений? - person Xuan; 28.04.2011

Это должно сделать это, я думаю (хотя я на самом деле не проверял):

primaryjoin=sqlalchemy.and_(
    film_table.c.country_id==film_table.c.country_id,
    film_table.c.id!=film_table.c.id)
person Singletoned    schedule 15.04.2011
comment
Не совсем. Он не заменяет film_table.c.id на ? в сгенерированном sql. - person Xuan; 21.04.2011