【问题标题】:How to query in Django with best efficiency?如何以最佳效率在 Django 中查询?
【发布时间】:2019-06-11 11:03:11
【问题描述】:

我最近发现太多的SQL查询优化问题。 django-debug-tool 报告了数百个类似和重复的查询。因此,我试图找出 Django ORM 的最佳效率以避免不必要的查询集评估。

正如你在下面的 Store 模型中看到的,一个 Store 模型有很多外键和 ManyToManyFields。由于这种结构,有许多代码 sn-ps 对 HTML 模板文件进行打击,例如 store.image_set.allstore.top_keywords.all。一切都以store. 开头。在每个商店详细信息页面中,我只是通过prefetch_related 或select_related 传递一个缓存的商店对象。这是一个不好的方法吗?我应该在 views.py 上分别缓存和 prefetch_related 或 select_related 每个外键或 ManyToManyField 吗?

HTML 模板

{% for img in store.image_set.all %}
  {{ img }}
{% endfor %}
{% for top_keyword in store.top_keywords.all %}
  {{ top_keyword }}
{% endfor %}
{% for sub_keyword in store.sub_keywords.all %}
  {{ sub_keyword }}
{% endfor %}

views.py

class StoreDetailView(View):

    def get(self, request, *args, **kwargs):

        cache_name_store = 'store-{0}'.format(store_domainKey)
        store = cache.get(cache_name_store, None)
        if not store:
            # query = get_object_or_404(Store, domainKey=store_domainKey)
            query = Store.objects.all().prefetch_related('image_set').get(domainKey=store_domainKey)
            cache.set(cache_name_store, query)
            store = cache.get(cache_name_store)

        context = {
            'store': store,
        }
        return render(request, template, context)

models.py

class Store(TimeStampedModel):

    categories = models.ManyToManyField(Category, blank=True)
    price_range = models.ManyToManyField(Price, blank=True)

    businessName = models.CharField(unique=True, max_length=40,
                                    verbose_name='Business Name')

    origin = models.ForeignKey(Origin, null=True, on_delete=models.CASCADE, blank=True)
    ship_to = models.ManyToManyField(ShipTo, blank=True)

    top_keywords = models.ManyToManyField(Keyword, blank=True, related_name='store_top_keywords')
    sub_keywords = models.ManyToManyField(SubKeyword, blank=True, related_name='store_sub_keywords')

    sponsored_stores = models.ManyToManyField(
        'self', through='Sponsorship', symmetrical=False, related_name='sponsored_store_of_store')
    similar_stores = models.ManyToManyField(
        'self', through='Similarity', symmetrical=False, related_name='similar_store_of_store')


    shortDesc = models.TextField(blank=True, verbose_name='Short Description')
    longDesc = models.TextField(blank=True, verbose_name='Long Description')

    returnPol = models.TextField(verbose_name='Return Policy', blank=True)
    returnUrl = models.CharField(max_length=255, null=True, blank=True, verbose_name='Return Policy URL')

    likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, editable=False)

    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
                                   related_name='stores_of_created_by', null=True, blank=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE,
                                   related_name='stores_of_updated_by', null=True, blank=True)

【问题讨论】:

    标签: django


    【解决方案1】:

    我真的不建议自定义缓存/性能优化,除非这是最后的手段。 Django 在 querysetsoptimisation 上有很好的文档 - 如果您遵循这些文档,那么您应该很少遇到需要自定义解决方法的主要性能问题。

    认为这里的问题是您在模板中打印对象并因此调用它们的str() 方法。这没有任何问题,但我会检查您在 str() 方法中使用的变量。我怀疑你在引用其他模型? IE。图像模型(或其他)中的 str() 方法正在执行类似于 image.field.other_field 的操作。在这种情况下,您的查询应如下所示:

    queryset = Store.objects.prefetch_related('image_set__field')

    您的最终查询集可能如下所示:

    queryset = Store.objects.prefetch_related('image_set__field1', 'image_set__field2', 'top_keywords__field3', ...)

    请注意,您仍然可以将其传递给 get_object_or_404,如下所示:

    get_object_or_404(queryset, pk=<your_stores_id>)
    

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2012-02-09
      • 2015-06-11
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      • 2022-01-25
      • 2021-09-22
      • 2023-03-16
      • 1970-01-01
      相关资源
      最近更新 更多