简体   繁体   English

Django中复杂多模型查询的优化

[英]Optimization of complex multi-model query in Django

I need an easy control of what products shown on which site, and since there are lots of products, I would also like to set product sites via category, producer and tags. 我需要轻松控制在哪个站点上显示的产品,并且由于有很多产品,我还想通过类别,生产者和标签设置产品站点。 So I show a product on a site if the product OR (its category AND its producer AND one of its tags) are linked to the site. 因此,如果产品OR(其类别及其生产者及其标签之一)链接到该网站,我会在网站上显示产品。 The code I ended up with is the following (simplified): 我最终得到的代码如下(简化):

from django.db.models import Model, ManyToManyField, ForeignKey, BooleanField

class Site(Model):
    enabled = BooleanField()

class Producer(Model):
    sites = ManyToManyField(Site)

class Category(Model):
    sites = ManyToManyField(Site)

class Tag(Model):
    sites = ManyToManyField(Site)

class Product(Model):
    producer = ForeignKey(Producer)
    category = ForeignKey(Category)
    tags     = ManyToManyField(Tag)
    sites    = ManyToManyField(Site)

    def get_site_ids(self):
        if self.sites.exists():
            return list(self.sites.values_list('id', flat=True))
        else:
            p = list(self.producer.sites.values_list('id', flat=True))
            c = list(self.category.sites.values_list('id', flat=True))
            t = sum([list(tag.sites.values_list('id', flat=True)) for tag in self.tags.all()], [])
            ids = set.intersection(set(p), set(c), set(t))
            return ids

My question is how can I optimize get_sites method? 我的问题是如何优化get_sites方法? Is it possible to join some of the queries? 是否可以加入一些查询?


Update: I am interested just in site ids which will be indexed and stored by search engine. 更新:我对仅由搜索引擎索引和存储的网站ID感兴趣。

You should try and do everything you want to do on the database level if possible. 如果可能,您应该尝试在数据库级别上执行您想要执行的所有操作。 Something like this should get you started. 这样的事情应该让你开始。

from django.db.models import Sum
self.objects.select_related("producer__sites",
                            "category__sites",
                            "tags__sites",
                            "sites").annotate(tag_count=Sum("tags__sites__id"))

select_related returns the Product model with the producer, category, tags and sites references filled. select_related返回Product模型,其中填充了生产者,类别,标签和站点引用。 This also includes the sites reference in producer, category and tags. 这还包括生产者,类别和标签中的sites参考。 This make Django do less queries to the database. 这使得Django对数据库的查询更少。

annotate adds an attribute to the returned Model instance named tag_count that has the Sum of tags_ sites _id in it. annotate向返回的名为tag_count Model实例添加一个属性,该实例中包含tags_ sites _id的Sum。

The Django QuerySet Reference might be a good help because I don't know the exact nature of what you want to have returned. Django QuerySet Reference可能是一个很好的帮助,因为我不知道你想要返回的确切性质。

Yes you can reduce the number of queries in Django using select_related and/or prefetch_related . 是的,您可以使用select_related和/或prefetch_related减少Django中的查询数量。

However, the select_related only works for foreign key and one-on-one relationships. 但是, select_related仅适用于外键和一对一关系。 Since you have ManyToMany in your Product model, you should use prefetch_related to reduce your queries in Product.get_sites(). 由于您的Product模型中有ManyToMany,因此您应该使用prefetch_related来减少Product.get_sites()中的查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM