Невозможно определить взаимозависимые отношения между моделями с помощью SQLAlchemy

#python #sqlalchemy #flask-sqlalchemy

Вопрос:

В следующих примерах кода ChatMessage модель имеет обязательное поле converstaion_id , которое определяет связь с ChatConversation этой моделью. ChatConverstation модель имеет поле last_message_id , которое является ссылкой на последнее ChatMessage .

Я получаю следующее сообщение об ошибке sqlalchemy и не знаю, как решить эту проблему. Пожалуйста, помогите.

sqlalchemy.exc.InvalidRequestError: При инициализации сопоставления сопоставленного класса ChatConversation->chat_conversation выражению «ChatMessage» не удалось найти имя («ChatMessage»). Если это имя класса, подумайте о добавлении этой связи() вChatConversation’> класс после определения обоих зависимых классов.

Как я должен определить схему для этих моделей, чтобы я мог установить обе взаимосвязи (т. Е. conversation отношения в ChatMessage модели и last_message отношения в ChatConversation модели) ?

 class ChatConversation(db.Model):
  __tablename__ = 'chat_conversation'

  id = db.Column(db.Integer, primary_key=True)
  last_message_id = db.Column(
      db.Integer,
      db.ForeignKey("chat_message.id", ondelete='SET NULL'),
      nullable = True
  )
  last_message = db.relationship('ChatMessage')
 
 class ChatMessage(db.Model):
  __tablename__ = 'chat_message'

  id = db.Column(db.Integer, primary_key=True)
  conversation_id = db.Column(
      db.Integer,
      db.ForeignKey("chat_conversation.id", ondelete='CASCADE'),
      nullable=False
  )
  conversation = db.relationship('ChatConversation')
 

Комментарии:

1. У вас не может быть циклических ссылок на внешние ключи. Не допускается. Отчасти это сделало бы невозможным безопасное удаление некоторых записей. Вы можете сделать его целым числом.

2. Если я удалю ограничение внешнего ключа last_message_id , смогу ли я заполнять данные в last_message отношениях без каких-либо проблем?

3. Я верю в это, но вам придется делать это как целое число, а не как ChatMessage экземпляр.

4. Спасибо, что предупредили. Я определил отношения с помощью hybrid_propery .

Ответ №1:

Решение состоит в том, чтобы использовать hybrid_property декоратор метода из sqlalchemy и foreign_keys явно определить, чтобы устранить неоднозначность ForeignKey .

 
from sqlalchemy.ext.hybrid import hybrid_property

class ChatConversation(db.Model):
  __tablename__ = 'chat_conversation'

  id = db.Column(db.Integer, primary_key=True)
  last_message_id = db.Column(
      db.Integer,
      db.ForeignKey("chat_message.id", ondelete='SET NULL'),
      nullable = True
  )
  
  @hybrid_property
  def last_message(self):
    return False if not self.last_message_id else ChatMessage.query.get(self.last_message_id)

 
 class ChatMessage(db.Model):
  __tablename__ = 'chat_message'

  id = db.Column(db.Integer, primary_key=True)
  conversation_id = db.Column(
      db.Integer,
      db.ForeignKey("chat_conversation.id", ondelete='CASCADE'),
      nullable=False
  )
  conversation = db.relationship('ChatConversation', foreign_keys = [conversation_id])