Как отфильтровать внешний ключ с помощью ModelMultipleChoiceFilter в DRF?

У меня возникают проблемы с использованием ModelMultipleChoiceFilter в DRF.

Во-первых, у меня есть три модели.

# JUST STRUCTURE
class A -> fields : [user:User]
class B -> fields : [a:A(related_name="b"), c:C]
class C -> fields : [name:string]

И я хочу отфильтровать имена C (множественный выбор) в классе A.

Так... в views.py,

class ShortFormListCreateView(generics.ListCreateAPIView):
   queryset = A.objects.all()
   filter_backends = [DjangoFilterBackend]
   filterset_class = AFilterSet

и в filters.py,

class AFilterSet(FilterSet):
    aa = filters.ModelMultipleChoiceFilter(
        field_name='b__c__name',
        to_field_name='name',
        lookup_expr='in',
        queryset=C.objects.all(),
        method='filter_cc',
        widget=CSVWidget,
    )

    class Meta:
        model = ShortForm
        fields = ['aa']

    def filter_cc(self, queryset, name, value):
        c_ids = [v.id for v in value]
        if value:
            queryset = queryset.filter(b__c__in=c_ids).distinct()
        return queryset

Это сработало, но я думаю, что это не эффективный способ. Есть ли какие-нибудь решения?

Оптимизация оценки кверисетов: Убедитесь, что оценка наборов запросов эффективна, особенно при работе со связанными моделями. Это включает использование select_related или prefetch_related, где это уместно, чтобы минимизировать запросы к базе данных

Настройте поведение виджета: В зависимости от потребностей фронтенда, вы можете настроить поведение виджета. Например, если вам нужен выпадающий выбор для нескольких вариантов, вы можете использовать SelectMultiple вместо CSVWidget

Упрощение определений фильтров: Если определение фильтра становится сложным, подумайте о том, чтобы разбить его на более мелкие классы или функции фильтра, которые можно использовать повторно. Это может улучшить читаемость и сопровождаемость кода

# views.py
from django.db.models import Prefetch

class ShortFormListCreateView(generics.ListCreateAPIView):
    queryset = A.objects.select_related('user').prefetch_related(
        Prefetch('b_set', queryset=B.objects.select_related('c'))
    )
    filter_backends = [DjangoFilterBackend]
    filterset_class = AFilterSet

# filters.py
from django_filters import Filter, FilterSet

class NameFilter(Filter):
    def filter(self, qs, value):
        if value:
            names = value.split(',')  # Assuming CSV input
            return qs.filter(b__c__name__in=names)
        return qs

class AFilterSet(FilterSet):
    aa = NameFilter(field_name='b__c__name', label='C Names')

    class Meta:
        model = A
        fields = ['aa']
Вернуться на верх