Using a GenericRelation
to map Record
s to Person
s, I have the following code, which works correctly, but there is a performance problem I am trying to address:
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):
...
In summary I have:
RecordX ===GenericRelation===> PersonRecordMapping ===ForeignKey===> Person
The display logic in my application follows these relationships to display all the Person
s mapped to each RecordX
:
views.py
@rendered_with('template.html')
def show_all_recordXs(request):
recordXs = RecordX.objects.all()
return { 'recordXs': recordXs }
The problem comes in the template:
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 %}
As indicated, every time I request the Person
s related to the RecordX
, it generates a new query. I cannot seem to figure out how prefetch these initially to avoid the redundant queries.
If I try selected_related
, I get an error that no selected_related
fields are possible here (error message: Invalid field name(s) given in select_related: 'xxx'. Choices are: (none)
). Not surprising, I now see -- there aren't any FKs on this model.
If I try prefetch_related('people')
, no error is thrown, but I still get the same repeated queries on every loop in the template as before. Likewise for prefetch_related('people__person')
. If I try prefetch_related('personrecordmapping')
, I get an error.
Along the lines of this answer, I considered doing trying to simulate a select_related
via something like:
PersonRecordMapping.objects.filter(object_id__in=RecordX.objects.values_list('id', flat=True))
but I don't understand the _content_object_cache
well enough to adapt this answer to my situation (if even the right approach).
So -- how can I pre-fetch all the Person
s to the RecordX
s to avoid n queries when the page will display n RecordX
objects?
Thanks for your help!
Ack, apparently I needed to call both -- prefetch_related('people', 'people__person')
. SIGH.