Fitler DateTimeField с фильтром даты в django-фильтр

#python #django #django-filter

#питон #джанго #django-фильтр

Вопрос:

У меня есть модель, которая имеет create_date , update_date , release_date DateTimeField.

Я хотел бы иметь фильтр для их DateTimeField DateFilter фильтрации . Вот один из способов, которым я могу это сделать:

 class ProductFilter(django_filters.FilterSet):
    
    create_date = DateFilter(field_name='create_date', lookup_expr='date')
    create_date__gt = DateFilter(field_name='create_date', lookup_expr='date__gt')
    create_date__lt = DateFilter(field_name='create_date', lookup_expr='date__lt')
    create_date__gte = DateFilter(field_name='create_date', lookup_expr='date__gte')
    create_date__lte = DateFilter(field_name='create_date', lookup_expr='date__lte')
    
    update_date = DateFilter(field_name='update_date', lookup_expr='date')
    update_date__gt = DateFilter(field_name='update_date', lookup_expr='date__gt')
    update_date__lt = DateFilter(field_name='update_date', lookup_expr='date__lt')
    update_date__gte = DateFilter(field_name='update_date', lookup_expr='date__gte')
    update_date__lte = DateFilter(field_name='update_date', lookup_expr='date__lte')

    release_date = DateFilter(field_name='release_date', lookup_expr='date')
    release_date__gt = DateFilter(field_name='release_date', lookup_expr='date__gt')
    release_date__lt = DateFilter(field_name='release_date', lookup_expr='date__lt')
    release_date__gte = DateFilter(field_name='release_date', lookup_expr='date__gte')
    release_date__lte = DateFilter(field_name='release_date', lookup_expr='date__lte')

 

Вы можете увидеть, что все становится повторяющимся. Есть ли какой-нибудь способ инкапсулировать логику?

P.S. Я знаю, что могу использовать Meta.fields , как:

 class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = {
            'create_date': ['date', 'date__gt', 'date__lt', 'date__gte', 'date__lte'],
            'update_date': ['date', 'date__gt', 'date__lt', 'date__gte', 'date__lte'],
            'release_date': ['date', 'date__gt', 'date__lt', 'date__gte', 'date__lte'],
        }
 

но имя фильтра станет create_date__date вместо create_date .

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

1. Вы можете использовать только lte и gte для меньших и больших значений. т.е. ['exact', 'let's, 'gte'] exact поиск проверит точную дату.

Ответ №1:

Вы можете переопределить __init__(...) метод FilterSet класса как,

 field_names = ["create_date", "update_date", "release_date"]
lookup_expr = ["gt", "lt", "gte", "lte"]
filter_dict = {}
for field_name in field_names:
    filter_dict[field_name] = DateFilter(lookup_expr="date")
    for expr in lookup_expr:
        filter_dict[f"{field_name}_{expr}"] = DateFilter(
            field_name=field_name,
            lookup_expr=f"date__{expr}"
        )


class FooFilter(filters.FilterSet):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.filters.update(filter_dict) 

Ответ №2:

Вы можете определить метод класса, который задает атрибуты. Но вы должны вызвать его где-нибудь, например, сразу после его определения.

 class ProductFilter(django_filters.FilterSet):
    @classmethod
    def init_attr(klass):
        field_names = ["create_date", "update_date", "release_date"]
        lookup_expr = ["", "__gt", "__lt", "__gte", "__lte"]
        
        for field_name in field_names:
            for expr in lookup_expr:
                setattr(klass, field_name expr, DateFilter(field_name=field_name, lookup_expr='date' expr))
PoductFilter.init_attr()