如何为 Django 过滤器创建 link
How to create link for django filter
场景:
产品可以在数据库中定义多个属性,我希望能够按这些属性进行过滤。
由于我还没有找到使用 django-filter 使用动态属性的方法,目前这是通过使用 django 过滤器 MethodFilter
来实现的,它将作为查询字符串传递的属性解析为:
/products?attribute=size_2&attribute=color_red
url 这样的解析成功了
问题是构建 url:
我找不到构建 url 的合理方法,它会考虑当前搜索参数和 add/replace 这些参数。
Django 似乎强迫我使用 urlconf 但 django-filter 使用查询字符串参数。
我试图实现的是:
用户在页面 /products?attribute=size_10
上显示该尺寸的所有产品。
当他点击 link "color red" 时,新的 url 变成: /products?attribute=size_10&attribute=color_red
你能告诉我 django 的实现方式 吗?
如果您在中间件中包含 "django.core.context_processors.request",
然后 request.get 可在您的模板中访问。
然后您可以构建一个过滤器,它将 return 在构建您正在谈论的 link 时需要的 'GET' 变量。
这是我做的代码:
@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)
然后在模板中我这样使用它:
{% lessonapp_preserved_filters adm_url '1' %}
也许你可以尝试使用一些 js 解决方案。
只需使用 js 构建字典从 url 获取所有当前属性。
当点击其他属性按钮时,可以添加或替换dict中的属性。
- 使用这个字典来组成你的url。
最后我解决了,虽然解决方案很冗长。
上下文
我想要一个多选过滤器,用户可以在其中过滤产品的品牌。
请注意,如果我每次点击多选框时页面都刷新就可以了。
主要思想
我为多项选择中的每个字段构建了不同的 link,方法是在视图中为过滤器中的每个 link 手动添加搜索参数。每次页面刷新都会创建新的link,具体取决于多选中的哪个选项被选中。
代码
views.py看起来像这样
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)
基本上,每个过滤器都是一个 url,其中包含查询参数。因此,我通过添加或删除参数为每个 link 构建一个不同的 url,具体取决于 link 是否处于活动状态。
search.html 看起来像这样:
<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 %}
其中 my_index 是模板过滤器
from django import template
register = template.Library()
@register.filter
def my_index(List, i):
return List[int(i)]
场景:
产品可以在数据库中定义多个属性,我希望能够按这些属性进行过滤。
由于我还没有找到使用 django-filter 使用动态属性的方法,目前这是通过使用 django 过滤器 MethodFilter
来实现的,它将作为查询字符串传递的属性解析为:
/products?attribute=size_2&attribute=color_red
url 这样的解析成功了
问题是构建 url:
我找不到构建 url 的合理方法,它会考虑当前搜索参数和 add/replace 这些参数。
Django 似乎强迫我使用 urlconf 但 django-filter 使用查询字符串参数。
我试图实现的是:
用户在页面 /products?attribute=size_10
上显示该尺寸的所有产品。
当他点击 link "color red" 时,新的 url 变成: /products?attribute=size_10&attribute=color_red
你能告诉我 django 的实现方式 吗?
如果您在中间件中包含 "django.core.context_processors.request",
然后 request.get 可在您的模板中访问。
然后您可以构建一个过滤器,它将 return 在构建您正在谈论的 link 时需要的 'GET' 变量。
这是我做的代码:
@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)
然后在模板中我这样使用它:
{% lessonapp_preserved_filters adm_url '1' %}
也许你可以尝试使用一些 js 解决方案。
只需使用 js 构建字典从 url 获取所有当前属性。
当点击其他属性按钮时,可以添加或替换dict中的属性。
- 使用这个字典来组成你的url。
最后我解决了,虽然解决方案很冗长。
上下文
我想要一个多选过滤器,用户可以在其中过滤产品的品牌。 请注意,如果我每次点击多选框时页面都刷新就可以了。
主要思想
我为多项选择中的每个字段构建了不同的 link,方法是在视图中为过滤器中的每个 link 手动添加搜索参数。每次页面刷新都会创建新的link,具体取决于多选中的哪个选项被选中。
代码
views.py看起来像这样
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)
基本上,每个过滤器都是一个 url,其中包含查询参数。因此,我通过添加或删除参数为每个 link 构建一个不同的 url,具体取决于 link 是否处于活动状态。
search.html 看起来像这样:
<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 %}
其中 my_index 是模板过滤器
from django import template
register = template.Library()
@register.filter
def my_index(List, i):
return List[int(i)]