Using Django 1.8 on Python 3.4.1 with models:
class Product(models.Model):
name = models.CharField(max_length=255)
# some more fields here
def _
You will find this approach very useful:
project/admin.py
from django.contrib import admin
from django.contrib.admin.options import BaseModelAdmin
from django.db.models.constants import LOOKUP_SEP
class AdminBaseWithSelectRelated(BaseModelAdmin):
"""
Admin Base using list_select_related for get_queryset related fields
"""
list_select_related = []
def get_queryset(self, request):
return super(AdminBaseWithSelectRelated, self).get_queryset(request).select_related(*self.list_select_related)
def form_apply_select_related(self, form):
for related_field in self.list_select_related:
splitted = related_field.split(LOOKUP_SEP)
if len(splitted) > 1:
field = splitted[0]
related = LOOKUP_SEP.join(splitted[1:])
form.base_fields[field].queryset = form.base_fields[field].queryset.select_related(related)
class AdminInlineWithSelectRelated(admin.TabularInline, AdminBaseWithSelectRelated):
"""
Admin Inline using list_select_related for get_queryset and get_formset related fields
"""
def get_formset(self, request, obj=None, **kwargs):
formset = super(AdminInlineWithSelectRelated, self).get_formset(request, obj, **kwargs)
self.form_apply_select_related(formset.form)
return formset
class AdminWithSelectRelated(admin.ModelAdmin, AdminBaseWithSelectRelated):
"""
Admin using list_select_related for get_queryset and get_form related fields
"""
def get_form(self, request, obj=None, **kwargs):
form = super(AdminWithSelectRelated, self).get_form(request, obj, **kwargs)
self.form_apply_select_related(form)
return form
class FilterWithSelectRelated(admin.RelatedFieldListFilter):
list_select_related = []
def field_choices(self, field, request, model_admin):
return [
(getattr(x, field.remote_field.get_related_field().attname), str(x))
for x in self.get_queryset(field)
]
def get_queryset(self, field):
return field.remote_field.model._default_manager.select_related(*self.list_select_related)
app/admin.py
from django.contrib import admin
from project.admin import AdminWithSelectRelated, AdminInlineWithSelectRelated, FilterWithSelectRelated
from .models import FormaPago, Comprobante, ItemServicio, ItemBazar
class ItemServicioInlineAdmin(AdminInlineWithSelectRelated):
model = ItemServicio
list_select_related = (
'alumno_servicio__alumno__estudiante__profile',
'alumno_servicio__servicio__grado',
'comprobante__forma_pago',
)
class ItemBazarInlineAdmin(AdminInlineWithSelectRelated):
model = ItemBazar
list_select_related = (
'alumno_item__alumno__estudiante__profile',
'alumno_item__item__anio_lectivo',
'comprobante__forma_pago',
)
class ComprobanteAdmin(AdminWithSelectRelated):
list_display = ('__str__', 'total', 'estado', 'fecha_generado', 'forma_pago', 'tipo', )
list_filter = ('estado', 'forma_pago', )
list_select_related = ('forma_pago', )
inlines = (ItemServicioInlineAdmin, ItemBazarInlineAdmin, )
class AlumnoFilter(FilterWithSelectRelated):
list_select_related = ('estudiante__profile', )
class ItemServicioAdmin(AdminWithSelectRelated):
list_display = ('nombre', 'alumno', 'monto_pagado', 'comprobante', )
list_filter = (
'alumno_servicio__alumno__seccion__grado',
('alumno_servicio__alumno', AlumnoFilter),
)
list_select_related = (
'comprobante__forma_pago',
'alumno_servicio__alumno__estudiante__profile',
'alumno_servicio__alumno__seccion__grado',
'alumno_servicio__servicio__grado',
)
class ItemBazarAdmin(AdminWithSelectRelated):
list_display = ('nombre', 'alumno', 'monto_pagado', 'comprobante', )
list_filter = (
'alumno_item__alumno__seccion__grado',
('alumno_item__alumno', AlumnoFilter),
)
list_select_related = (
'comprobante__forma_pago',
'alumno_item__alumno__estudiante__profile',
'alumno_item__alumno__seccion__grado',
'alumno_item__item__anio_lectivo',
)
admin.site.register(FormaPago)
admin.site.register(Comprobante, ComprobanteAdmin)
admin.site.register(ItemServicio, ItemServicioAdmin)
admin.site.register(ItemBazar, ItemBazarAdmin)
All I have to do is define the select_related fields, and the Custom AdminWithSelectRelated, AdminInlineWithSelectRelated, and FilterWithSelectRelated make use of them for Changelists, Changeforms, and even inline Formsets.
Works like a charm.