如何向Django过滤器添加非模型字段

huangapple go评论61阅读模式
英文:

How add non model field to django filters

问题

I have a view with pagination and filtering that displays a list of products. I would like to provide the user with the option to choose between displaying all the products they can buy or displaying only the products they have already purchased.

show_products.py

def show_products(previously_purchased, user):
    if previously_purchased:
        transactions = Transaction.objects.filter(user_id=user).values_list('product_id')
        return Product.objects.filter(pk__in=[q[0] for q in transactions])
    return Product.objects.all()

models.py

class Product(models.Model):
    name = models.CharField(max_length=255)
    ...

views.py

class ProductList(ListView):
    ...
    def dispatch(self, request, *args, **kwargs):
        return super(ProductList, self).dispatch(request, *args, **kwargs)
    def get_queryset(self):
        self.filterset = ProductFilter(
            self.request.GET,
            queryset=show_products(previously_purchased=) # show_products(previously_purchased=show_)
        )
        return self.filterset.qs
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.filterset.form
        context['products'] = show_products(previously_purchased=)
        return context

filters.py

class ProductFilter(django_filters.FilterSet):
    CHOICE = {
        ('True', 'previously purchased'),
        ('False', 'all')
    }
    name = django_filters.CharFilter()
    
    class Meta:
        model = Product
        fields = ['name']
    

The show_products(previously_purchased=) function is responsible for creating a queryset of all products or only previously purchased ones, using the previously_purchased parameter.

Unfortunately, when I add previously_purchased in ProductFilter, I get an error saying that the previously_purchased field does not exist in the Product model.

When I add @property in the Product model, and intercept self.request.GET['previously_purchased'] to change the show_products() parameter, the display works fine. But the pagination stops working.

英文:

I have a view with pagination and filtering that displays a list of products. I would like to provide the user with the option to choose between displaying all the products they can buy or displaying only the products they have already purchased.

show_products.py

def show_products(previously_purchased, user):
    if previously_purchased:
        transactions = Transaction.objects.filter(user_id=user).values_list('product_id')
        return Product.objects.filter(pk__in=[q[0] for q in transactions])
    return Product.objects.all()

models.py

class Product(models.Model):
    name = models.CharField(max_length=255)
    ...

views.py

class ProductList(ListView):
    ...
    def dispatch(self, request, *args, **kwargs):
        return super(ProductList, self).dispatch(request, *args, **kwargs)
    def get_queryset(self):
        # show_ = True if 'previously_purchased' in  self.request.GET and self.request.GET['previously_purchased'] == 'True' else False
        self.filterset = ProductFilter(
            self.request.GET,
            queryset=show_products(previously_purchased=) # show_products(previously_purchased=show_)
        )
        return self.filterset.qs
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = self.filterset.form
        context['products'] = show_products(previously_purchased=)
        return context

filters.py

class ProductFilter(django_filters.FilterSet):
    CHOICE = {
        ('True', 'previously purchased'),
        ('False', 'all')
    }
    name = django_filters.CharFilter()
    # previously_purchased = django_filters.ChoiceFilter(choices=CHOICE)
    
    class Meta:
        model = Product
        fields = ['name']
    

The show_products(previously_purchased=) function is responsible for creating a queryset of all products or only previously purchased ones, using the previously_purchased parameter.

Unfortunately, when I add previously_purchased in ProductFilter, I get an error saying that the previously_purchased field does not exist in the Product model.

When I add @property in the Product model, and intercept self.request.GET['previously_purchased'] to change the show_products() parameter, the display works fine. But the pagination stops working.

答案1

得分: 1

以下是您要翻译的内容:

django-filter 中,您可以在字段内指定名为 method 的关键字参数,该参数接受可调用对象或方法的名称,因此您可以像这样修改您的 ProductFilter

class ProductFilter(django_filters.FilterSet):
    CHOICE = {
        ('True', 'previously purchased'),
        ('False', 'all')
    }
    name = django_filters.CharFilter()
    previously_purchased = django_filters.ChoiceFilter(
                             choices=CHOICE,
                             method='filter_previously_purchased',
                           )
    def filter_previously_purchased(self, queryset, name, value):
        if value == 'True':
            transactions = Transaction.objects.filter(user_id=self.request.user).values_list('product_id')
            queryset = queryset.filter(pk__in=[q[0] for q in transactions])
        return queryset
    
    class Meta:
        model = Product
        fields = ['name', 'previously_purchased',]

在上述代码中,我已将您的 show_products() 逻辑添加到 filter_previously_purchased 函数中,该函数接受以下参数:

  • queryset 这是指定的 model 的查询集,例如 Product.objects.all()
  • name 这是字段名称,例如 previously_purchased
  • value 这是来自客户端的值。
英文:

In django-filter you can specify keyword argument named as method inside field which accepts either a callable or the name of a method so you camodify you ProductFilter like this

class ProductFilter(django_filters.FilterSet):
    CHOICE = {
        ('True', 'previously purchased'),
        ('False', 'all')
    }
    name = django_filters.CharFilter()
    previously_purchased = django_filters.ChoiceFilter(
                             choices=CHOICE,
                             method='filter_previously_purchased',
                           )
    def filter_previously_purchased(self, queryset, name, value):
        if value == 'True':
            transactions = Transaction.objects.filter(user_id=self.request.user).values_list('product_id')
            queryset = queryset.filter(pk__in=[q[0] for q in transactions])
        return queryset
    
    class Meta:
        model = Product
        fields = ['name', 'previously_purchased',]

In above code I've added your show_products() logic inside filter_previously_purchased function with which takes these arguments

  • queryset It is queryset of specified model eg. Product.objects.all()
  • name it's a field name eg. previously_purchased
  • value it's value which comes from client.

huangapple
  • 本文由 发表于 2023年5月21日 22:56:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76300506.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定