Как вы делаете многие ко многим с более чем 2 таблицами?

У меня есть таблица для журналов, которая содержит различную информацию о сотрудниках, например:

class Log(Model):
    division_id = Column(Integer, ForeignKey('division.id'), nullable=False)
    division = relationship("Division")

    employee_id = Column(Integer, ForeignKey("employee.id"), nullable=False)
    employee = relationship("Employee") 

    skill_id = Column(Integer, ForeignKey("skill.id"), nullable=False)
    skill = relationship("Skill")

    message = Column(String, default='OK', nullable=False)
    date = Column(DateTime, default=NowTime(), nullable=True)

Таблицы сотрудников и навыков выглядят следующим образом:

class Employee(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)
    division_id = Column(Integer, ForeignKey('division.id'), nullable=False)
    division = relationship("Division")

class Skill(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)

В настоящее время я использую Flask-Appbuilder, и у меня есть представление навыков, в котором отображаются все журналы для текущего выбранного навыка.

class LogView(ModelView):
    datamodel = SQLAInterface(Log)
    list_columns = ['division', 'employee', 'skill', 'message', 'date']
    show_template = 'appbuilder/general/model/show_cascade.html'

class SkillLogView(ModelView):
    datamodel = SQLAInterface(Skill)
    list_columns = ['name']
    related_views = [LogView]
    show_template = 'appbuilder/general/model/show_cascade.html'

В SkillLogView я также хочу отобразить список имен сотрудников, у которых есть этот навык.

Как мне также получить сотрудников из журналов, которые относятся к текущему навыку?

Я не уверен, как это сделать, но я думал, что это может быть случай для многих ко многим. Проблема в том, что там 3 таблицы, а не 2.

Есть ли способ сделать многие ко многим с более чем двумя таблицами?

Или есть другой способ выполнить то, что я хочу сделать?

Любая помощь приветствуется.


person Caveman Coder    schedule 06.10.2017    source источник


Ответы (2)


Ваш Employee не установил никаких отношений с Log, поэтому запрос Employee с использованием соединения с Log для предиката затруднен.

Однако вы можете просто запросить Log для employee_id с skill_id в качестве подзапроса и получить Employee с заданным результатом.

# Subquery returns `employee_id` from `logs` with the given `skill_id`
sq = session.query(Log.employee_id).\
    filter(Log.skill_id == skill_id).\
    subquery()

# Fetch `Employee` that matches `employee_id` in `sq`
q = session.query(Employee).\
    filter(Employee.employee_id.in_(sq))

employees = q.all()  # or paginate, e.g. q.limit(..).all()
person Ivan Choo    schedule 06.10.2017
comment
Спасибо за помощь Иван! Кроме того, я опубликовал еще один метод, который реализует его на уровне модели таблицы. Проверьте это, когда у вас будет время. - person Caveman Coder; 06.10.2017
comment
Спасибо, что поделился. Я упомянул ваш Your Employee has not established any relationship with Log..., это именно то, что защищает ваш другой метод. - person Ivan Choo; 06.10.2017

В Интернете есть пример, который делает именно это!

В нем есть таблица людей, таблица автомобилей, таблица владельцев автомобилей.

Все, что мне нужно было сделать, это заменить сотрудника на человека, навык на автомобиль и журнал на владение автомобилем.

URL-адрес ссылки: Many-to -Многие с объектом ассоциации и всеми определенными отношениями аварийно завершают работу при удалении

Обновленный код:

class Log(Model):
    division_id = Column(Integer, ForeignKey('division.id'), nullable=False)
    division = relationship("Division")

    employee_id = Column(Integer, ForeignKey("employee.id"), nullable=False)
    employee = relationship("Employee", backref=backref('log', passive_deletes='all'))

    skill_id = Column(Integer, ForeignKey("skill.id"), nullable=False)
    skill = relationship("Skill", backref=backref('log', passive_deletes='all'))

    message = Column(String, default='OK', nullable=False)
    date = Column(DateTime, default=NowTime(), nullable=True)


class Skill(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)

    employees = relationship('Employee', secondary='log', backref='skill')


class Employee(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)

    division_id = Column(Integer, ForeignKey('division.id'), nullable=False)
    division = relationship("Division")

    skills = relationship('Skill', secondary='log', backref='employee')
person Caveman Coder    schedule 06.10.2017