Как запросить несколько таблиц в SQLAlchemy ORM

Я новичок в SQLAlchemy ORM и изо всех сил пытаюсь выполнить сложные запросы к нескольким таблицам - запросы, которые я считаю относительно простыми в Doctrine DQL.

У меня есть объекты данных Города, принадлежащие Странам. В некоторых городах также установлен идентификатор округа, но не во всех. Помимо необходимых первичных и внешних ключей, каждая запись также имеет text_string_id, который ссылается на таблицу TextStrings, в которой хранится название города / округа / страны на разных языках. Таблица TextStrings MySQL выглядит следующим образом:

CREATE TABLE IF NOT EXISTS `text_strings` (
    `id` INT UNSIGNED NOT NULL,
    `language` VARCHAR(2) NOT NULL,
    `text_string` varchar(255) NOT NULL,
    PRIMARY KEY (`id`, `language`)
)

Я хочу построить для каждого города цепочку навигации в форме:

country_en_name> city_en_name OR

country_en_name> county_en_name> city_en_name,

в зависимости от того, установлен ли для этого города атрибут округа. В Doctrine это было бы относительно просто:

    $query = Doctrine_Query::create()
                ->select('ci.id, CONCAT(cyts.text_string, \'> \', IF(cots.text_string is not null, CONCAT(cots.text_string, \'> \', \'\'), cits.text_string) as city_breadcrumb')
                ->from('City ci')
                ->leftJoin('ci.TextString cits')
                ->leftJoin('ci.Country cy')
                ->leftJoin('cy.TextString cyts')
                ->leftJoin('ci.County co')
                ->leftJoin('co.TextString cots')
                ->where('cits.language = ?', 'en')
                ->andWhere('cyts.language = ?', 'en')
                ->andWhere('(cots.language = ? OR cots.language is null)', 'en');

С SQLAlchemy ORM я изо всех сил пытаюсь добиться того же. Мне кажется, что я правильно настроил объекты - например, в форме:

class City(Base):
    __tablename__ = "cities"

    id = Column(Integer, primary_key=True)
    country_id = Column(Integer, ForeignKey('countries.id'))
    text_string_id = Column(Integer, ForeignKey('text_strings.id'))
    county_id = Column(Integer, ForeignKey('counties.id'))

    text_strings = relation(TextString, backref=backref('cards', order_by=id))
    country = relation(Country, backref=backref('countries', order_by=id))
    county = relation(County, backref=backref('counties', order_by=id))

Моя проблема заключается в запросах - я пробовал различные подходы к созданию хлебных крошек, но, похоже, ничего не работает. Некоторые наблюдения:

Возможно, использование таких вещей, как CONCAT и IF, встроенное в запрос, не очень питонично (возможно ли это даже с ORM?) - поэтому я попытался выполнить эти операции вне SQLAlchemy, в цикле записей Python . Однако здесь я изо всех сил пытался получить доступ к отдельным полям - например, аксессоры модели, похоже, не заходят на n уровней, например City.counties.text_strings.language не существует.

Я также экспериментировал с использованием кортежей - ближе всего к этому у меня получилось разбить его на два запроса:

# For cities without a county
for city, country in session.query(City, Country).\
    filter(Country.id == City.country_id).\
    filter(City.county_id == None).all():

    if city.text_strings.language == 'en':
    # etc

# For cities with a county
for city, county, country in session.query(City, County, Country).\
    filter(and_(City.county_id == County.id, City.country_id == Country.id)).all():

    if city.text_strings.language == 'en':
    # etc

Я разделил его на два запроса, потому что я не мог понять, как сделать присоединение костюма необязательным в одном запросе. Но этот подход, конечно, ужасен, и, что еще хуже, второй запрос не работал на 100% - он не объединял все разные строки city.text_strings для последующей фильтрации.

Так я в тупике! Любая помощь, которую вы можете мне оказать, направив меня на правильный путь для выполнения такого рода сложных запросов в SQLAlchemy ORM, была бы очень признательна.

5
задан Alex Dean 16 January 2011 в 13:19
поделиться