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

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

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

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

models.py

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

views.py

  1. class ProductList(ListView):
  2. ...
  3. def dispatch(self, request, *args, **kwargs):
  4. return super(ProductList, self).dispatch(request, *args, **kwargs)
  5. def get_queryset(self):
  6. self.filterset = ProductFilter(
  7. self.request.GET,
  8. queryset=show_products(previously_purchased=) # show_products(previously_purchased=show_)
  9. )
  10. return self.filterset.qs
  11. def get_context_data(self, **kwargs):
  12. context = super().get_context_data(**kwargs)
  13. context['form'] = self.filterset.form
  14. context['products'] = show_products(previously_purchased=)
  15. return context

filters.py

  1. class ProductFilter(django_filters.FilterSet):
  2. CHOICE = {
  3. ('True', 'previously purchased'),
  4. ('False', 'all')
  5. }
  6. name = django_filters.CharFilter()
  7. class Meta:
  8. model = Product
  9. 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

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

models.py

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

views.py

  1. class ProductList(ListView):
  2. ...
  3. def dispatch(self, request, *args, **kwargs):
  4. return super(ProductList, self).dispatch(request, *args, **kwargs)
  5. def get_queryset(self):
  6. # show_ = True if 'previously_purchased' in self.request.GET and self.request.GET['previously_purchased'] == 'True' else False
  7. self.filterset = ProductFilter(
  8. self.request.GET,
  9. queryset=show_products(previously_purchased=) # show_products(previously_purchased=show_)
  10. )
  11. return self.filterset.qs
  12. def get_context_data(self, **kwargs):
  13. context = super().get_context_data(**kwargs)
  14. context['form'] = self.filterset.form
  15. context['products'] = show_products(previously_purchased=)
  16. return context

filters.py

  1. class ProductFilter(django_filters.FilterSet):
  2. CHOICE = {
  3. ('True', 'previously purchased'),
  4. ('False', 'all')
  5. }
  6. name = django_filters.CharFilter()
  7. # previously_purchased = django_filters.ChoiceFilter(choices=CHOICE)
  8. class Meta:
  9. model = Product
  10. 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

  1. class ProductFilter(django_filters.FilterSet):
  2. CHOICE = {
  3. ('True', 'previously purchased'),
  4. ('False', 'all')
  5. }
  6. name = django_filters.CharFilter()
  7. previously_purchased = django_filters.ChoiceFilter(
  8. choices=CHOICE,
  9. method='filter_previously_purchased',
  10. )
  11. def filter_previously_purchased(self, queryset, name, value):
  12. if value == 'True':
  13. transactions = Transaction.objects.filter(user_id=self.request.user).values_list('product_id')
  14. queryset = queryset.filter(pk__in=[q[0] for q in transactions])
  15. return queryset
  16. class Meta:
  17. model = Product
  18. 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

  1. class ProductFilter(django_filters.FilterSet):
  2. CHOICE = {
  3. ('True', 'previously purchased'),
  4. ('False', 'all')
  5. }
  6. name = django_filters.CharFilter()
  7. previously_purchased = django_filters.ChoiceFilter(
  8. choices=CHOICE,
  9. method='filter_previously_purchased',
  10. )
  11. def filter_previously_purchased(self, queryset, name, value):
  12. if value == 'True':
  13. transactions = Transaction.objects.filter(user_id=self.request.user).values_list('product_id')
  14. queryset = queryset.filter(pk__in=[q[0] for q in transactions])
  15. return queryset
  16. class Meta:
  17. model = Product
  18. 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:

确定