There are two things you can do to speed up the loading of this page.
- Set
DEBUG = False
.
- Cache the database queries used in the rendering of the inline model.
DEBUG = False
The reason that the page loads slowly is that the Django admin is rendering a subtemplate for every instance of the inline model. With 75 instances of the inline model, you are rendering 75 extra templates, even if there is minimal content in them. While rendering a template is normally very fast, if you have DEBUG = True
, you incur extra overhead for every template you render because Django is injecting extra context for its debug-mode error page (this is about 0.4 seconds per template on my system). This extra overhead is normally not noticeable because you are normally only rendering a handful of templates for a single page. When you render 75 templates, however, this adds up to a noticeable delay (75 * 0.4 seconds = 30 seconds).
Caching database queries
At least as of Django 1.10, the inline model will make any necessary database queries to render it for each instance of the inline model. If your inline model has any foreign keys on the inline model, this can pretty inefficient if you have a slow database connection. The technique is to run database queries for the choices of these foreign keys when you initialize the instance of the inline class (using get_formsets_with_inlines
), and then replace the choices of these fields on the inline with the cached values to prevent repeating this database query (using formfield_for_foreignkey
).
class Manufacturer(models.Model):
...
class OperatingSystem(models.Model):
...
class Computer(models.Model):
manufacturer = models.ForeignKey(Manufarturer)
owner = models.ForeignKey(User)
operating_system = models.ForeignKey(OperatingSystem)
...
class ComputerAdmin(admin.StackedInline):
model = Computer
def formfield_for_foreignkey(self, db_field, request, **kwargs):
field = super(ComputerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == "owner" and hasattr(self, "cached_owners"):
field.choices = self.cached_owners
elif db_field.name == "manufacturer" and hasattr(self, "cached_manufacturers"):
field.choices = self.cached_manufacturers
elif db_field.name == "operating_system" and hasattr(self, "cached_operating_systems"):
field.choices = self.cached_operating_systems
return field
class ManufacturerAdmin(admin.ModelAdmin):
inlines = (ComputerAdmin,)
def get_formsets_with_inlines(self, request, obj=None):
for inline in self.get_inline_instances(request, obj):
inline.cached_owners = [(i.pk, str(i)) for i in User.objects.all()]
inline.cached_manufacturers = [(i.pk, str(i)) for i in Manufacturer.objects.all()]
inline.cached_operating_systems = [(i.pk, str(i)) for i in OperatingSystem.objects.all()]
yield inline.get_formset(request, obj), inline