SQLAlchemy / Elixir - запрос проверки членства объекта в списке отношений «многие ко многим» - PullRequest
1 голос
/ 11 июня 2011

Я пытаюсь создать запрос sqlalchemy, чтобы получить список имен всех профессоров, которые являются ассистентами профессора в MIT.Обратите внимание, что с одним курсом может быть связано несколько профессоров-ассистентов.

То, что я пытаюсь сделать, примерно эквивалентно:

uni_mit = University.get_by(name='MIT')
s = select([Professor.name],
           and_(Professor.in_(Course.assistants),
                Course.university = uni_mit))
session.execute(s)

Это не сработает, потому что in_ определяется только для полей сущности, а не для всей сущности. Не может использовать Professor.id.in_, так как Course.assistants - это список профессоров, а не список их идентификаторов.Я также пытался contains, но я тоже не работал.

Моя модель Elixir:

class Course(Entity):
    id = Field(Integer, primary_key=True)
    assistants = ManyToMany('Professor', inverse='courses_assisted', ondelete='cascade')
    university = ManyToOne('University')
    ..

class Professor(Entity):
    id = Field(Integer, primary_key=True)
    name = Field(String(50), required=True)
    courses_assisted = ManyToMany('Course', inverse='assistants', ondelete='cascade')
    ..

Это было бы тривиально, если бы я мог получить доступ к промежуточной сущности "многие ко многим"(условие будет and_(interm_table.prof_id = Professor.id, interm_table.course = Course.id), но SQLAlchemy, по-видимому, скрывает эту таблицу от меня.

Я использую Elixir 0.7 и SQLAlchemy 0.6.

Кстати: этот вопрос отличается от Sqlalchemy + elixir: Как выполнить запрос с отношением ManyToMany? в том, что мне нужно проверить профессоров по всем курсам, которые удовлетворяют условию, а не по одному, статическому.

1 Ответ

0 голосов
/ 11 июня 2011

Вы можете найти промежуточную таблицу, где Elixir скрыл ее, но обратите внимание, что она использует полные имена столбцов (например, __package_path_with_underscores__course_id).Чтобы избежать этого, определите ManyToMany, например,

class Course(Entity):
    ...
    assistants = ManyToMany('Professor', inverse='courses_assisted',
                            local_colname='course_id', remote_colname='prof_id',
                            ondelete='cascade')

, а затем вы можете получить доступ к промежуточной таблице, используя

rel = Course._descriptor.find_relationship('assistants')
assert rel
table = rel.table

, и получить доступ к столбцам, используя table.c.prof_id и т. Д.

Обновление: Конечно, вы можете сделать это на более высоком уровне, но не в одном запросе, потому что SQLAlchemy еще не поддерживает in_ для отношений.Например, с двумя запросами:

>>> mit_courses = set(Course.query.join(
... University).filter(University.name == 'MIT'))
>>> [p.name for p in Professor.query if set(
... p.courses_assisted).intersection(mit_courses)]

Или, альтернативно:

>>> plist = [c.assistants for c in Course.query.join(
... University).filter(University.name == 'MIT')]
>>> [p.name for p in set(itertools.chain(*plist))]

На первом шаге создается список списков помощников.Второй шаг сглаживает список списков и удаляет дубликаты путем создания набора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...