Django admin inline: select_related

前端 未结 4 587
[愿得一人]
[愿得一人] 2020-12-14 04:52

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 _         


        
4条回答
  •  庸人自扰
    2020-12-14 05:10

    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.

提交回复
热议问题