Поиск_expr для динамических имен полей в Django Rest Framework

#python #django-rest-framework

#python #django-rest-framework

Вопрос:

Модель:

 class EmployeeModel(models.Model):

    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
  

Сериализатор:

 class EmployeeSerializer(serializers.ModelSerializer):

    class Meta:
        model = EmployeeModel
        fields = '__all__'
  

Viewset:

 class EmployeeViewSet(viewsets.ModelViewSet):
    
    queryset = EmployeeModel.objects.all()
    serializer_class = EmployeeSerializer
    filterset_class = EmployeeFilterSet
  

Мой EmployeeFilterSet выглядит следующим образом:

 class EmployeeFilterSet(django_filters.FilterSet):
   
    first_name__equals = django_filters.CharFilter(method='get_first_name_equals', field_name='first_name')
    last_name__equals = django_filters.CharFilter(method='get_last_name_equals', field_name='last_name')

    def get_first_name_equals(self, queryset, field_name, value):
        query = Q()
        for q_query in [Q(first_name__iexact=name) for name in (value.split(',') if value else [])]:
            query |= q_query
        return queryset.filter(query).all()

     def get_last_name_equals(self, queryset, field_name, value):
        query = Q()
        for q_query in [Q(last_name__iexact=name) for name in (value.split(',') if value else [])]:
            query |= q_query
        return queryset.filter(query).all()
  

Как мы можем видеть, оба get_first_name_equals и get_last_name_equals имеют похожие определения. Единственная причина, по которой у меня разные методы, заключается в том, что выражения поиска имеют разные имена полей first_name__iexact и last_name__iexact в выражении цикла for. Есть ли способ, с помощью которого я могу использовать один метод, такой как get_equals(), и сформировать выражение поиска в выражении цикла for на основе переданного field_name? Это помогло бы избежать написания нескольких функций, выполняющих аналогичное выражение поиска, но с разными именами полей.

Комментарии:

1. Рассматривали ли вы возможность использования field_name в dict расширении using — например **{f"{field_name}__iexact": name} ?

2. @Rfroes87 спасибо за ответ. Я не понимаю, как именно мне нужно это сделать. Я пробовал это, но не работает : for q_query in [Q{f"{field_name}__iexact": name} for name in (value.split(',') if value else [])]: . Не могли бы вы помочь мне с функцией о том, как именно это можно сделать? Это было бы очень полезно.

3. Измените его на for q_query in [Q(**{f"{field_name}__iexact": name}) for name in (value.split(',') if value else [])]: и повторите попытку.

Ответ №1:

Вы можете использовать универсальную функцию, которая (уже) получает field_name и создает dict на ее основе объединенную с __iexact .

Это будет работать следующим образом:

 class EmployeeFilterSet(django_filters.FilterSet):
   
    first_name__equals = django_filters.CharFilter(method='get_field_equals', field_name='first_name')
    last_name__equals = django_filters.CharFilter(method='get_field_equals', field_name='last_name')

    def get_field_equals(self, queryset, field_name, value):
        query = Q()
        for q_query in [Q(**{f"{field_name}__iexact": name}) for name in (value.split(',') if value else [])]:
            query |= q_query
        return queryset.filter(query).all()
  

После расширения dict с ** аргументами Q объект будет выглядеть как предполагаемый Q(first_name__iexact=name) и так далее.