通过 GenericRelation 上的 ForeignKey 缓存 Django 查询
Django query caching through a ForeignKey on a GenericRelation
使用 GenericRelation
将 Record
s 映射到 Person
s,我有以下代码,它工作正常,但我试图解决一个性能问题:
models.py
class RecordX(Record): # Child class
....
class Record(models.Model): # Parent class
people = GenericRelation(PersonRecordMapping)
def people_all(self):
# Use select_related here to minimize the # of queries later
return self.people.select_related('person').all()
class Meta:
abstract = True
class PersonRecordMapping(models.Model):
person = models.ForeignKey(Person)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Person(models.Model):
...
总而言之我有:
RecordX ===GenericRelation===> PersonRecordMapping ===ForeignKey===> Person
我的应用程序中的显示逻辑遵循这些关系来显示映射到每个 RecordX
:
的所有 Person
views.py
@rendered_with('template.html')
def show_all_recordXs(request):
recordXs = RecordX.objects.all()
return { 'recordXs': recordXs }
问题出在模板中:
template.html
{% for recordX in recordXs %}
{# Display RecordX's other fields here #}
<ul>
{% for map in record.people_all %}{# <=== This generates a query every time! #}
<li>{{ map.person.name }}</li>
{% endfor %}
</ul>
{% endfor %}
如前所述,每次我请求与 RecordX
相关的 Person
时,它都会生成一个新查询。我似乎无法弄清楚最初如何预取这些以避免冗余查询。
如果我尝试 selected_related
,我会收到一条错误消息,指出此处不可能有 selected_related
字段(错误消息:Invalid field name(s) given in select_related: 'xxx'. Choices are: (none)
)。不足为奇,我现在明白了——这个模型上没有任何 FK。
如果我尝试 prefetch_related('people')
,不会抛出任何错误,但我仍然会像以前一样在模板中的每个循环中得到相同的重复查询。 prefetch_related('people__person')
也是如此。如果我尝试 prefetch_related('personrecordmapping')
,我会得到一个错误。
沿着 this answer 的路线,我考虑过尝试通过以下方式模拟 select_related
:
PersonRecordMapping.objects.filter(object_id__in=RecordX.objects.values_list('id', flat=True))
但我对 _content_object_cache
的理解还不够深入,无法根据我的情况调整此答案(即使是正确的方法)。
那么——当页面将显示 n RecordX
个对象?
感谢您的帮助!
Ack,显然我需要调用 both -- prefetch_related('people', 'people__person')
。叹息。
使用 GenericRelation
将 Record
s 映射到 Person
s,我有以下代码,它工作正常,但我试图解决一个性能问题:
models.py
class RecordX(Record): # Child class
....
class Record(models.Model): # Parent class
people = GenericRelation(PersonRecordMapping)
def people_all(self):
# Use select_related here to minimize the # of queries later
return self.people.select_related('person').all()
class Meta:
abstract = True
class PersonRecordMapping(models.Model):
person = models.ForeignKey(Person)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Person(models.Model):
...
总而言之我有:
RecordX ===GenericRelation===> PersonRecordMapping ===ForeignKey===> Person
我的应用程序中的显示逻辑遵循这些关系来显示映射到每个 RecordX
:
Person
views.py
@rendered_with('template.html')
def show_all_recordXs(request):
recordXs = RecordX.objects.all()
return { 'recordXs': recordXs }
问题出在模板中:
template.html
{% for recordX in recordXs %}
{# Display RecordX's other fields here #}
<ul>
{% for map in record.people_all %}{# <=== This generates a query every time! #}
<li>{{ map.person.name }}</li>
{% endfor %}
</ul>
{% endfor %}
如前所述,每次我请求与 RecordX
相关的 Person
时,它都会生成一个新查询。我似乎无法弄清楚最初如何预取这些以避免冗余查询。
如果我尝试 selected_related
,我会收到一条错误消息,指出此处不可能有 selected_related
字段(错误消息:Invalid field name(s) given in select_related: 'xxx'. Choices are: (none)
)。不足为奇,我现在明白了——这个模型上没有任何 FK。
如果我尝试 prefetch_related('people')
,不会抛出任何错误,但我仍然会像以前一样在模板中的每个循环中得到相同的重复查询。 prefetch_related('people__person')
也是如此。如果我尝试 prefetch_related('personrecordmapping')
,我会得到一个错误。
沿着 this answer 的路线,我考虑过尝试通过以下方式模拟 select_related
:
PersonRecordMapping.objects.filter(object_id__in=RecordX.objects.values_list('id', flat=True))
但我对 _content_object_cache
的理解还不够深入,无法根据我的情况调整此答案(即使是正确的方法)。
那么——当页面将显示 n RecordX
个对象?
感谢您的帮助!
Ack,显然我需要调用 both -- prefetch_related('people', 'people__person')
。叹息。