самореферентная связь sqlalchemy, не включающая ‘self’

#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.