我的一个列表页面中有一个用于提供 unicode 功能的相关模型。 我试图预取以防止重复查询。
预取查询如下:
SELECT "pansys_modulex"."id", "pansys_modulex"."client", "pansys_modulex"."change_date", "pansys_modulex"."changed_by_id", "pansys_modulex"."create_date", "pansys_modulex"."created_by_id", "pansys_modulex"."language_id", "pansys_modulex"."short_text", "pansys_modulex"."module_id" FROM "pansys_modulex" WHERE ("pansys_modulex"."language_id" = '3' AND "pansys_modulex"."module_id" IN ('8', '9', '10', '12', '13', '14'))
尽管如此,我还是会收到如下的数十个重复查询:
SELECT "pansys_modulex"."id", "pansys_modulex"."client", "pansys_modulex"."change_date", "pansys_modulex"."changed_by_id", "pansys_modulex"."create_date", "pansys_modulex"."created_by_id", "pansys_modulex"."language_id", "pansys_modulex"."short_text", "pansys_modulex"."module_id" FROM "pansys_modulex" WHERE ("pansys_modulex"."language_id" = '3' AND "pansys_modulex"."module_id" = '8')
我在这里错过了什么? 我以为我会预取查询,如果可以的话,django会尝试使用预取结果。
编辑: 我的模型和预取命令本身。
#models trimmed
class Application(GenericCommonModel):
module = models.ForeignKey(Module, verbose_name=_('Module'))
class Module(GenericCommonModel):
def __unicode__(self):
short_text = None
try:
language = PanBasLanguage.objects.get(language=get_language())
short_text = ModuleX.objects.get(module = self,language = language).short_text
except ModuleX.DoesNotExist:
print 'ModuleX > DoesNotExist'
return short_text or self.abbreviation
class ModuleX(models.Model):
module = custom_model_fields.PanNotNullForeignKey(Module, on_delete=models.CASCADE)
language = custom_model_fields.PanNotNullForeignKey('panbas.PanBasLanguage')
short_text = custom_model_fields.PanShortTextField()
class Meta:
verbose_name = _('Module Description')
verbose_name_plural = _('Module Descriptions')
unique_together = ('module', 'language')
class PanBasLanguage(GenericBasicModel):
language_choices = settings.LANGUAGES
language = custom_model_fields.PanNoneBlankCharField(choices=language_choices, max_length=8,
verbose_name=_('Language'), unique=True)
#in my view
language = PanBasLanguage.objects.get(language=get_language())
x_result = ModuleX.objects.filter(language=language)
prefetch = Prefetch('module__modulex_set', queryset=x_result)
queryset = queryset.prefetch_related(prefetch)
简而言之,语言模型有可用的语言,Module有ModuleX模型来保持不同语言的short_texts。在我的应用程序列表中,我打印出一个列中的模块,这个模块单独进行模块查找。
答案 0 :(得分:2)
简而言之,语言模型有可用的语言,Module有ModuleX模型来保持不同语言的short_texts。在我的应用程序列表中,我打印出一个列中的模块,这个模块单独进行模块查找。
所以你要找的是模块对象,你想要用给定语言的短文本。
现在,从Module对象接近它然后处理反向外键是很自然的。但是,由于语言限制将始终在关系的许多方面生成一个结果,因此最好从多方面处理此问题,就像现在一样。作为奖励,您可以使用select_related
作为Escher指出。
根据Module上的过滤的复杂程度,您可能希望使用两个查询(仍然消除循环内的查询)。
所以,这是一种方式:
ModuleX.objects.filter(language__language=get_language(), **module_filters).select_related('module')
其中**module_filters
是对模块的过滤。你可以用一个小包装器来做到这一点:
def _get_module_filters(self, **kwargs):
filters = {}
for k, v in **kwargs:
filters['module__' + k] = v
return filters
这节省了一些输入,并允许您专注于查询模块而不是语言包装器。
两种查询方式是:
modules = Module.objects.filter(**module_filters)
translations = ModuleX.objects.filter(language__language=get_language(),
module__in=modules).select_related('module')
请注意,如果您在模块实例上调用str()
,则会再次获得其他查询,因为您在那里执行相同的工作。这包括模板代码,如:
{% for obj in translations %}
{{ obj.module }}
{% endfor %}
translations
是上述查询集。
答案 1 :(得分:1)
来自the docs:
select_related(* fields)返回一个“跟随”外键关系的QuerySet,在执行查询时选择其他相关对象数据。这是一个性能提升器,它会导致单个更复杂的查询,但意味着以后使用外键关系不需要数据库查询。
和
另一方面,prefetch_related 对每个关系进行单独查找,并在Python中进行“加入”。这允许它预取多对多和多对一对象,除了select_related支持的外键和一对一关系之外,这些对象无法使用select_related完成。
鉴于您的是外键关系,而不是m2m,您应该使用i
进行该查询。