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.
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.