簡體   English   中英

由 django 中的 prefetch_related 完成的燒瓶多對多連接

[英]flask many to many join as done by prefetch_related from django

我在帶有 Sql Alchemy ORM 的燒瓶中有以下組和聯系人模型

group_contact = db.Table(
    'group_contact',
    db.Column('group_id', db.Integer, db.ForeignKey(
        'group.id')),
    db.Column('contact_id', db.Integer, db.ForeignKey(
        'contact.id')),
    db.PrimaryKeyConstraint('group_id', 'contact_id')
)


class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))


class Contact(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    phone = db.Column(db.String(15), nullable=False, unique=True)
    groups = db.relationship(
        "Group", secondary=group_contact, backref='contacts')

現在我需要查詢與組的聯系:

contacts = Contact.query.join(Group, Contact.groups).all()
for contact in contacts:
    print(contact.groups)

這里的問題是當我執行上面的代碼時,SQL 查詢的數量隨着聯系數量的增加而增加。

Django ORM 有 prefetch_related() 和 queryset,它根據 django docs執行以下操作。

另一方面,prefetch_related 對每個關系進行單獨的查找,並在 Python 中進行“連接”。 除了 select_related 支持的外鍵和一對一關系之外,這允許它預取使用 select_related 無法完成的多對多和多對一對象。

現在我正在嘗試通過以下代碼對 Sql Alchemy 做同樣的事情:

contacts = Contact.query.all()     
contact_groups = group_contact.query.join(
    Group
).filter(group_contact.contact_id.in_([item.id for item in contacts]))

但這給了我這個錯誤:

AttributeError: 'Table' object has no attribute 'query'

如何使用 SqlAlchemy 從 django 獲取 prefetch_related 之類的功能?

您想告訴 SQLAlchemy 使用關系加載技術急切加載相關對象。 可以告訴 SQLAlchemy 在單個查詢中加載組和聯系人。

對於這一個查詢,您可以添加joinedload()選項(可通過Flask-SQLAlchemy db對象獲得):

contacts = Contact.query.options(db.joinedload(Contact.groups)).all()

這會在每個匹配的聯系人上預加載Contact.groups屬性:

for contact in contacts:
    # no new query issued to fetch groups, the data for the groups
    # is already available
    print(contact.groups)

執行的查詢如下所示:

SELECT 
    contact.id AS contact_id,
    contact.phone AS contact_phone,
    group_1.id AS group_1_id,
    group_1.name AS group_1_name
FROM contact 
LEFT OUTER JOIN (
    group_contact AS group_contact_1
    JOIN "group" AS group_1 ON group_1.id = group_contact_1.group_id
) ON contact.id = group_contact_1.contact_id

您還可以為模型上的關系設置默認加載策略; 要始終急切地加載組,請在關系上使用lazy='joined'

class Contact(db.Model):
    # ...
    groups = db.relationship(
        "Group", secondary=group_contact, backref='contacts',
        lazy='joined')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM