Условное заполнение выпадающего списка в бэкенде Django с помощью list_filters

Мой models.py:

from smart_selects.db_fields import ChainedForeignKey

class Funder(models.Model):
    name = models.CharField(max_length=200)
    scheme = models.ManyToManyField('Scheme', blank=True)

class Scheme(models.Model):
    name = models.CharField(max_length=200)

class Project(models.Model):

    funder = models.ForeignKey(Funder, on_delete=models.PROTECT)
    scheme = ChainedForeignKey(
        Scheme,
        chained_field="funder",
        chained_model_field="funder",
        show_all=False,
        auto_choose=True,
        sort=True, null=True, blank=True)

Как вы можете видеть, я уже использую smart-selects для получения только схем, которые принадлежат данному конкретному фонду, доступных в Project выпадающем выборе в бэкенде администратора. smart-selects, однако, не заботится о том, что происходит в list_filters разделе админки.

Что я хотел бы достичь: имею два "цепных" выпадающих фильтра в моей таблице Project admin, где я фильтрую проекты, которые имеют определенного спонсора, и как только я отфильтровал такие проекты, я хочу видеть только scheme, которые принадлежат этому конкретному funder в выпадающем schemes, с возможностью более тщательной фильтрации проектов с этой конкретной схемой.

Моя неудачная попытка (admin/py):

from admin_auto_filters.filters import AutocompleteFilter, AutocompleteFilterFactory

class SchemeFilter(
    AutocompleteFilterFactory(
        'new Scheme', 'scheme'
    )
):
    def lookups(self, request, model_admin):
        funder = request.GET.get('funder__pk__exact', '')
        if funder:
            schemes= Scheme.objects.filter(funder__exact=funder).distinct()
        else:
            schemes = Scheme.objects.none()
        return schemes

    def queryset(self, request, queryset):

        funder = request.GET.get('funder__pk__exact', '')

        if funder and Scheme.objects.filter(funder__exact=funder).count():
            return queryset.filter(scheme__exact=self.value())

        return queryset

class FunderFilter(AutocompleteFilter):
    title = 'Funder'
    field_name = 'funder'

class ProjectAdmin(NumericFilterModelAdmin, ImportExportModelAdmin):
    search_fields = ['title', 'project_number']
    list_filter = [FunderFilter, SchemeFilter,]
[...]

Возможно, вы сможете сделать это, переопределив некоторые методы в классе ModelAdmin.

enter code here class ProjectAdmin(admin.ModelAdmin):
list_filter = ('funder', 'scheme')

def get_changelist_instance(self, request):
    changelist_instance = super().get_changelist_instance(request)
    funder_filter = changelist_instance.get_filters(request)[0][0]
    funder_id = funder_filter.used_parameters.get('funder', None)

    if funder_id:
        self.list_filter = (
            ('funder', admin.RelatedOnlyFieldListFilter),
            ('scheme', admin.RelatedOnlyFieldListFilter),
        )
    else:
        self.list_filter = ('funder',)

    return changelist_instance

В этом коде переопределите метод get_changelist_instance ModelAdmin. Вызовите метод get_changelist_instance родителя, чтобы получить экземпляр ChangeList. Затем получите фильтр funder и проверьте, был ли он использован (т. е. выбрал ли пользователь funder). Если он был выбран, мы устанавливаем атрибут list_filter таким образом, чтобы он включал фильтры funder и scheme. Если ни один из спонсоров не был выбран, мы включаем только фильтр спонсора.

Таким образом, фильтр схем появится только в том случае, если выбран спонсор, и в него будут включены только схемы, связанные с выбранным спонсором.

Вернуться на верх