Как я могу избавиться от ошибки циклической зависимости при создании базы данных в sqlalchemy?

Я новичок в использовании sqlalchemy. Как избавиться от ошибки циклической зависимости для таблиц, показанных ниже. В основном моя цель состоит в том, чтобы создать таблицу вопросов с ответом «один на один» «лучший ответ», чтобы ответить, и отношение «один к другому» «возможно».

class Answer(Base): __tablename__ = 'answers' id = Column(Integer, primary_key=True) text = Column(String) question_id = Column(Integer, ForeignKey('questions.id')) def __init__(self, text, question_id): self.text = text def __repr__(self): return "<Answer '%s'>" % self.text class Question(Base): __tablename__ = 'questions' id = Column(Integer, primary_key=True) text = Column(String) picture = Column(String) depth = Column(Integer) amount_of_tasks = Column(Integer) voting_threshold = Column(Integer) best_answer_id = Column(Integer, ForeignKey('answers.id'), nullable=True) possible_answers = relationship("Answer", post_update=True, primaryjoin = id==Answer.question_id) def __init__(self, text, picture, depth, amount_of_tasks): self.text = text self.picture = picture self.depth = depth self.amount_of_tasks = amount_of_tasks def __repr__(self): return "<Question, '%s', '%s', '%s', '%s'>" % (self.text, self.picture, self.depth, self.amount_of_tasks) def __repr__(self): return "<Answer '%s'>" % self.text 

Это сообщение об ошибке: CircularDependencyError: обнаружена циклическая зависимость. Циклы:

4 Solutions collect form web for “Как я могу избавиться от ошибки циклической зависимости при создании базы данных в sqlalchemy?”

По-видимому, SQLAlchemy не хорошо работает с круговыми зависимостями. Вместо этого вы можете использовать таблицу ассоциаций для представления наилучшего ответа …

 from sqlalchemy import Column, Integer, String, ForeignKey, create_engine from sqlalchemy import Table from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, sessionmaker engine = create_engine('sqlite:///:memory:') Base = declarative_base() class Answer(Base): __tablename__ = 'answer' id = Column(Integer, primary_key=True) question_id = Column(Integer, ForeignKey('question.id')) text = Column(String) question = relationship('Question', backref='answers') def __repr__(self): return "<Answer '%s'>" % self.text class Question(Base): __tablename__ = 'question' id = Column(Integer, primary_key=True) text = Column(String) best_answer = relationship('Answer', secondary=lambda: best_answer, uselist=False) def __repr__(self): return "<Question, '%s'>" % (self.text) best_answer = Table('best_answer', Base.metadata, Column('question_id', Integer, ForeignKey('question.id'), primary_key=True), Column('answer_id', Integer, ForeignKey('answer.id')) ) if __name__ == '__main__': session = sessionmaker(bind=engine)() Base.metadata.create_all(engine) question = Question(text='How good is SQLAlchemy?') somewhat = Answer(text='Somewhat good') very = Answer(text='Very good') excellent = Answer(text='Excellent!') question.answers.extend([somewhat, very, excellent]) question.best_answer = excellent session.add(question) session.commit() question = session.query(Question).first() print(question.answers) print(question.best_answer) 

Решение Mark работает, но я хотел найти способ сделать это, не создавая дополнительную таблицу. После обширного поиска я наконец нашел этот пример в документах:

http://docs.sqlalchemy.org/en/latest/orm/relationship_persistence.html (второй пример)

Подход состоит в том, чтобы использовать primaryjoin [1] для обеих отношений в модели Question и добавлять post_update=True в один из них. post_update сообщает post_update чтобы установить best_answer_id как дополнительный оператор UPDATE , best_answer_id круговую зависимость.

Вам также нужны foreign_keys указанные в question в модели Answer .

Ниже приведен код Марка, который соответствует приведенному выше примеру. Я тестировал его с помощью v1.1.9 .

 from sqlalchemy import Column, Integer, String, ForeignKey, create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, sessionmaker engine = create_engine('sqlite:///:memory:') Base = declarative_base() class Answer(Base): __tablename__ = 'answer' id = Column(Integer, primary_key=True) text = Column(String) question_id = Column(Integer, ForeignKey('question.id')) question = relationship('Question', back_populates='answers', foreign_keys=[question_id]) def __repr__(self): return "<Answer '%s'>" % self.text class Question(Base): __tablename__ = 'question' id = Column(Integer, primary_key=True) text = Column(String) best_answer_id = Column(Integer, ForeignKey('answer.id')) answers = relationship('Answer', primaryjoin= id==Answer.question_id) best_answer = relationship('Answer', primaryjoin= best_answer_id==Answer.id, post_update=True) def __repr__(self): return "<Question, '%s'>" % (self.text) if __name__ == '__main__': session = sessionmaker(bind=engine)() Base.metadata.create_all(engine) question = Question(text='How good is SQLAlchemy?') somewhat = Answer(text='Somewhat good') very = Answer(text='Very good') excellent = Answer(text='Excellent!') question.answers.extend([somewhat, very, excellent]) question.best_answer = excellent session.add(question) session.commit() question = session.query(Question).first() print(question.answers) print(question.best_answer) 

[1] Интересно, что «строковый формат» для primaryjoin видимому, вызывает ошибку, – но работает SQL-выражение с перегруженными операторами объектов столбца.

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

  class Answer(Base): __tablename__ = 'answers' id = Column(Integer, primary_key=True) text = Column(String) class Question(Base): __tablename__ = 'questions' id = Column(Integer, primary_key=True) text = Column(String) picture = Column(String) depth = Column(Integer) amount_of_tasks = Column(Integer) voting_threshold = Column(Integer) best_answer_id = Column(Integer, ForeignKey('answers.id'), nullable=True) Answer.question_id = Column(Integer, ForeignKey(Question.id)) Question.possible_answers = relationship(Answer, post_update=True, primaryjoin=Question.id==Answer.question_id) 

Это не слишком приятно, так как определение класса начинает немного всплывать, но это делает трюк.

Правильный способ – ForeignKeyConstraint(..., use_alter=True) .

http://docs.sqlalchemy.org/en/latest/core/constraints.html#sqlalchemy.schema.ForeignKeyConstraint.params.use_alter

  • Pylint не может найти элемент запроса SQLAlchemy
  • Как настроить таблицу с рекурсивным внешним ключом и отношения декларативно в SQLAlchemy?
  • SQLAlchemy 2 внешних ключа к одному и тому же первому ключу
  • Использование сеанса SQLAlchemy из Flask повышает «объекты SQLite, созданные в потоке, могут использоваться только в том же потоке»
  • Является ли SQLAlchemy по-прежнему рекомендуемым, если он используется только для сырого SQL-запроса?
  • Flask-SQLAlchemy проверяет наличие строки в таблице
  • SQLAlchemy create_all () не создает таблицы
  • Доля моделей sqlalchemy между флягой и другими приложениями
  • Python - лучший язык программирования в мире.