Scenario:
Products can have multiple attributes defined in the database, I want to be able to filter by those attributes.
Since i have not found a way to use dynamic attributes using django-filter, this is currently achieved by using django filter MethodFilter
which parses the attributes passed as query string as:
/products?attribute=size_2&attribute=color_red
url like this is parsed and it works.
The problem is building the url:
I couldn't find a reasonable way to build the url, that would take current search parameters into account and add/replace those parameters.
Django seems to be forcing me to use urlconf but django-filter uses query string parameters.
What i try to achieve is this:
The user is on page /products?attribute=size_10
which display all products with that size. When he clicks th link "color red" the new url becomes: /products?attribute=size_10&attribute=color_red
Can you point me to the django way of implementing this?
if you include "django.core.context_processors.request",
in your middleware then the request.get is accessible in your templates.
you could then build a filter that will return what 'GET' variables you want when building the link you are talking about.
here is code for one that i did:
@register.simple_tag(takes_context=True)
def lessonapp_preserved_filters(context, url, dayofweek):
opts = context.get('opts')
preserved_filters = context.get('preserved_filters')
parsed_url = list(urlparse(url))
parsed_qs = dict(parse_qsl(parsed_url[4]))
merged_qs = dict()
if opts and preserved_filters:
preserved_filters = dict(parse_qsl(preserved_filters))
match_url = '/%s' % url.partition(get_script_prefix())[2]
try:
match = resolve(match_url)
except Resolver404:
pass
else:
current_url = '%s:%s' % (match.app_name, match.url_name)
changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name)
if changelist_url == current_url and '_changelist_filters' in preserved_filters:
preserved_filters = dict(parse_qsl(preserved_filters['_changelist_filters']))
preserved_filters['dayofweek__exact'] = dayofweek
merged_qs.update(preserved_filters)
merged_qs.update(parsed_qs)
parsed_url[4] = urlencode(merged_qs)
return urlunparse(parsed_url)
and then in the template i use it like this:
{% lessonapp_preserved_filters adm_url '1' %}
maybe you try use some js solution.
just get all the current attributes from url by using js ,build dict.
when clicking other attribute button,you can add or replace the attribute in the dict.
At the end I solved, although the solution is pretty verbose.
I want a multiple choice filter, where the user can filter the brand of the products. Note that it is ok if the page refreshes every time I click on the multiple choice field.
I build a different link for each field in the multiple choice, by manually adding the search parameters in a view for each link in the filters. Every time the page refreshes new link are created, depending on which choice in the multiple choice is selected.
The views.py looks like this
from django.shortcuts import get_object_or_404, render
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from .models import Product, Brand
from django.db.models import Q
def search(request):
queryset_list = Product.objects.order_by('price')
# Keyworks
if 'search' in request.GET:
search = request.GET['search']
if search:
queryset_list = queryset_list.filter(Q(name__icontains=search) | Q(description__icontains=search))
path = request.path
link = path + '?' + 'search=' + search
# Brands filter
brands_list = []
for query in queryset_list:
if query.brand.name not in brands_list:
brands_list.extend([query.brand.name])
brand_urls = {}
brand_active = [False] * len(brands_list)
if 'brand' not in request.GET:
for brand in brands_list:
brand_urls[brand] = link + '&' + 'brand=' + brand
else:
active_filters = [f for f in request.GET['brand'].split(',')]
if len(active_filters) > 1:
queryset_list = queryset_list.filter(brand__name__in=active_filters)
for k, brand in enumerate(brands_list):
new_active_filters = active_filters.copy()
if brand in new_active_filters:
brand_active[k] = True
new_active_filters.remove(brand)
brand_urls[brand] = link + '&' + 'brand=' + ','.join(new_active_filters)
else:
brand_active[k] = False
new_active_filters.append(brand)
brand_urls[brand] = link + '&' + 'brand=' + ','.join(new_active_filters)
paginator = Paginator(queryset_list, 12)
page = request.GET.get('page')
paged_products = paginator.get_page(page)
context = {
'products': paged_products,
'values': request.GET,
'brand_urls': brand_urls,
'brand_active': brand_active,
}
return render(request, 'products/search.html', context)
basically, every filter is a url, that contains the query parameters. So I build a different url for every link by adding or removing parameters, depending if the link is active or not.
search.html looks like this:
<h2>Brands</h2>
{% if brand_urls %}
<ol>
{% for brand in brand_urls.items %}
{% if brand_active|my_index:forloop.counter0 is True %}
<li><input type="checkbox" checked><a href="{{ brand.1 }}">{{ brand.0 }}</a></li>
{% else %}
<li><input type="checkbox"><a href="{{ brand.1 }}">{{ brand.0 }}</a></li>
{% endif %}
{% endfor %}
</ol>
{% endif %}
where my_index is a template filter
from django import template
register = template.Library()
@register.filter
def my_index(List, i):
return List[int(i)]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.