Para mi modelo en particular, el aspecto particularmente lento es pasar por ForeignKeys cuando se muestran en formularios, que no se llaman usando select_related
, así que esa es la parte que voy a acelerar.
Mirando a través de la fuente de Django relevante, que se ve en django/contrib/admin/options.py
que el método formfield_for_foreignkeys
toma cada FK db_field
y llama al método ForeignKey
de clase formfield
, que se define en django/db/modelos/campos/relacionados/como:
def formfield(self, **kwargs):
db = kwargs.pop('using', None)
defaults = {
'form_class': forms.ModelChoiceField,
'queryset': self.rel.to._default_manager.using(db).complex_filter(self.rel.limit_choices_to),
'to_field_name': self.rel.field_name,
}
defaults.update(kwargs)
return super(ForeignKey, self).formfield(**defaults)
De esto, vemos si proporcionamos el db_field
con un kwargs['queryset']
podemos definir un queryset personalizado que se utilizará select_related (esto puede ser proporcionado por formfield_for_foreignkey
).
Así que básicamente lo que queremos hacer es anular admin.ModelAdmin
con SelectRelatedModelAdmin
y luego hacer que nuestros subclases ModelAdmin de SelectRelatedModelAdmin
en lugar de admin.ModelAdmin
class SelectRelatedModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if 'queryset' in kwargs:
kwargs['queryset'] = kwargs['queryset'].select_related()
else:
db = kwargs.pop('using', None)
kwargs['queryset'] = db_field.rel.to._default_manager.using(db).complex_filter(db_field.rel.limit_choices_to).select_related()
return super(SelectRelatedModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
este ejemplo de código no cubre administrador Inline
s o s ManyToManyField
o foreign_key recorrido en las funciones llamadas por readonly_fields
o consultas personalizadas de selección, pero un enfoque similar debería funcionar para esos casos.
Esto podría simplificarse 'get_field_queryset' (aunque es indocumentado y por lo tanto se podría cambiar en el futuro). –