基于函数的视图中如何返回多个自定义过滤器?
Looks like you're trying to use two separate FilterSets together in your view and template, but you're running into issues getting both to show up and work correctly. Let's break down the problem and fix it step by step.
The Issue with Your Current Code
Right now, you're initializing two filters (ProductFilter and MyTagFilter) against the original Product.objects.all() queryset, but you're not:
- Chaining the filters together to apply both sets of criteria to your products
- Passing both filter forms to your template so they render on the page
Solution 1: Combine Filters into a Single FilterSet (Recommended)
The cleanest approach is to create a single FilterSet that includes both your title filter and tag filter logic. This avoids having to manage multiple filters in your view and template.
Update your filters.py with a combined filter:
class CombinedProductFilter(django_filters.FilterSet): # Include your custom TagFilter here tags = TagFilter(field_name='tags__name') class Meta: model = Product # Include both fields you want to filter on fields = ['title', 'tags']
Then simplify your view to use this single filter:
def product_list(request): # Start with all products queryset = Product.objects.all() # Initialize the combined filter with request parameters product_filter = CombinedProductFilter(request.GET, queryset=queryset) # Pass the filter and filtered products to the template return render(request, 'cart/product-list.html', { 'filter': product_filter, 'products': product_filter.qs })
Your template can stay almost the same (just make sure you're displaying the filtered products):
<div class="row"> <div class="col-sm-12"> <form method="get"> {{ filter.form|crispy }} <button class="btn btn-sm amphibian-button-primary btn-block element-shadow img-audio">Submit</button> </form> </div> </div> <!-- Display the filtered products --> <div class="row mt-4"> {% for product in products %} <div class="col-md-4 mb-3"> <h5>{{ product.title }}</h5> <!-- Add other product details here --> </div> {% empty %} <p>No products match your filters.</p> {% endfor %} </div>
Solution 2: Keep Separate FilterSets and Combine Them in the View
If you need to keep the filters separate for some reason, you can chain them and combine their forms in the view:
Update your view to chain the filters and merge their forms:
from django import forms def product_list(request): queryset = Product.objects.all() # Apply the first filter, then pass its result to the second filter product_filter = ProductFilter(request.GET, queryset=queryset) tag_filter = MyTagFilter(request.GET, queryset=product_filter.qs) # Create a combined form by merging fields from both filters combined_form = forms.Form() combined_form.fields.update(product_filter.form.fields) combined_form.fields.update(tag_filter.form.fields) return render(request, 'cart/product-list.html', { 'combined_form': combined_form, 'products': tag_filter.qs })
Then update your template to use combined_form:
<div class="row"> <div class="col-sm-12"> <form method="get"> {{ combined_form|crispy }} <button class="btn btn-sm amphibian-button-primary btn-block element-shadow img-audio">Submit</button> </form> </div> </div> <!-- Display filtered products --> <div class="row mt-4"> {% for product in products %} <div class="col-md-4 mb-3"> <h5>{{ product.title }}</h5> <!-- Other product details --> </div> {% empty %} <p>No products found.</p> {% endfor %} </div>
Key Notes
- When chaining filters, make sure to pass the filtered queryset (
product_filter.qs) to the next filter, not the original queryset. This ensures both filters are applied. - If you use the combined Form approach, you might want to adjust the order of fields in the template. You can do this by manually rendering each field instead of using
|crispy, or by defining the order in a custom form.
内容的提问来源于stack exchange,提问作者Fabian H

