blog/content/2013/08/2013-08-06_help-i-have-too-many-django-manytomany-queries-fixed.rst
2022-10-16 23:34:35 -04:00

33 lines
1.9 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Help, I have too many Django ManyToMany Queries [FIXED]
#######################################################
:date: 2013-08-06 04:00
:author: tyrel
:category: Tech
:tags: python, django, bugs
:slug: 2013-08-06-help-i-have-too-many-django-manytomany-queries-fixed
:status: published
My boss tasked me with getting the load time of 90 seconds(HOLY CARP!) on one page down. First thing I did was install the Django Debug Toolbar to see what was really happening.
There are currently 2,000 users in the database, the way our model is setup is that a UserProfile can have other UserProfiles attached to it in one of three M2M relations, which in the Django Admin would cause 2,000 queries PER M2M field. This is very expensive as obviously you dont want 10,000 queries that each take 0.3ms to take place.
The solution, after a day and a half of research is to override the **formfield_for_manytomany** method in the Admin class for our UserProfile object.
Our solution is to prefetch for any M2M that are related to the current Model.
.. code:: python
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.__class__.__name__ == "ManyToManyField" and \
db_field.rel.to.__name__ == self.model.__name__:
kwargs['queryset'] = db_field.rel.to.objects.prefetch_related("user")
return super(UserProfileInline, self).formfield_for_manytomany(
db_field, request, **kwargs)
This goes inside our admin class **UserProfileInline(admin.StackedInline)**. Simple clean and easy to drop into another ModelAdmin with minimal changes.
Other things I pondered was to set all our M2Ms as raw_id_fields, then using Select2 or Chosen, query our UserProfiles when the related users were being selected. This would take a lot of load off the initial page load, but is more of a bandaid rather than a real fix.
I tried to override the Admin classs **def queryset(self, request):** but this was not affecting anything.