Я построил две модели Message
и EmailAddress
, которые связаны в соотношении «многие ко многим» с помощью таблицы MessageEmailAddress
.(Я использовал Model
класс для MessageEmailAddress
, потому что есть метаданные action
, связанные с отношением.) Эти relationships
все lazy=dynamic
.
Запуск метода экземпляра Message.add_email_address()
невероятно медленно, ок.1,5 секунды на объект !!Метод, который необходимо проверить, существует ли ранее существующее отношение (т. Е. Строка в MessageEmailAddress
), а если нет, то создать новое.
Как построить более производительные отношения между таблицами?Какой элемент моего кода вызывает такую медленную работу?
Я пробовал много других способов создания отношения «многие ко многим» со связанными метаданными - это единственный способ, который не вызывал ошибок.
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Message(db.Model):
"""A single message."""
id = db.Column(db.Integer, primary_key=True)
# Is there a way to dynamically create these?
_email_addresses = relationship(
"EmailAddress",
secondary="message_email_address", lazy='dynamic', backref=backref("_messages", lazy='dynamic'))
_email_addresses_from = relationship(
"EmailAddress",
primaryjoin="and_(Message.id==MessageEmailAddress.message_id, MessageEmailAddress.action=='from')",
secondary="message_email_address",
lazy='dynamic',
backref=backref('_messages_from', lazy='dynamic')
)
_email_addresses_to = relationship(
"EmailAddress",
primaryjoin="and_(Message.id==MessageEmailAddress.message_id, MessageEmailAddress.action=='to')",
secondary="message_email_address",
lazy='dynamic',
backref=backref('_messages_to', lazy='dynamic')
)
def add_email_address(self, email_str, action, name=None):
"""Setter method for all related EmailAddress objects.
Args:
email_str: A string, ex. "david@gmail.com"
action: A string describing header action, ex. "from"
name: Optional string for name of EmailAddress
"""
# Ensure connection between Message, EmailAddress, and action is unique
action_prop = '_email_addresses_' + action
pre_existing = getattr(self, action_prop).filter_by(email_address=email_str).all()
if pre_existing and len(pre_existing):
return
# Add new connection
email_address = EmailAddress.get_or_create(
email_address=email_str, create_kwargs=dict(name=name))
a = MessageEmailAddress(message_id=self.id, email_id=email_address.id, action=action)
db.session.add(a)
db.session.commit()
return email_address
class EmailAddress(db.Model, ModelMixin):
"""A single email address.
Relationships to Message: _messages, _messages_from, _messages_to, etc.
"""
id = db.Column(db.Integer, primary_key=True)
...
class MessageEmailAddress(db.Model):
# Join Message and EmailAddress tables
id = db.Column(db.Integer, primary_key=True)
message_id = db.Column(
db.Integer, db.ForeignKey('message.id'), nullable=False)
email_id = db.Column(
db.Integer, db.ForeignKey('email_address.id'), nullable=False)
action = db.Column(db.String(), nullable=False) # Ex. From, To, Bcc
message = db.relationship("Message", backref=backref("message_email_address", lazy='dynamic'))
email_address = db.relationship("EmailAddress", backref=backref("message_email_address", lazy='dynamic'))