我最近发现太多SQL查询优化问题。 django-debug-tool报告了数百个相似和重复的查询。因此,我试图找出Django ORM的最佳效率,以避免不必要的Queryset评估。
如下面的商店模型所示,商店模型具有许多外键和ManyToManyFields。由于这种结构,许多代码片段对HTML模板文件(例如store.image_set.all
或store.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)
答案 0 :(得分:1)
我真的不建议自定义缓存/性能优化,除非这是最后的选择。 Django在querysets和optimisation上都有出色的文档-如果您遵循这些文档,那么您很少会遇到需要自定义解决方法的主要性能问题。
我认为这里的问题是,您要在模板中打印对象,然后调用它们的str()
方法。这没有什么问题,但是我将检查您在str()
方法中使用的是什么变量。我怀疑您正在引用其他模型?即图像模型(或其他任何模型)中的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>)
希望这会有所帮助。