如何为django过滤器创建链接

时间:2015-01-05 11:37:17

标签: django python-2.7 django-filter

情景:

产品可以在数据库中定义多个属性,我希望能够按这些属性进行过滤。

由于我还没有找到使用django-filter来使用动态属性的方法,目前这是通过使用django filter MethodFilter实现的,它将作为查询字符串传递的属性解析为:

/products?attribute=size_2&attribute=color_red

像这样的网址被解析并且有效。

问题在于建立网址:

我找不到合理的方法来构建网址,这会考虑当前的搜索参数并添加/替换这些参数。

Django似乎强迫我使用urlconf,但django-filter使用查询字符串参数。

我试图实现的是:

用户在页面/products?attribute=size_10上显示所有具有该尺寸的产品。 当他点击“红色”链接时,新网址变为:/products?attribute=size_10&attribute=color_red

你能指点我实现这个的 django方式吗?

3 个答案:

答案 0 :(得分:0)

如果在中间件中包含"django.core.context_processors.request", 然后可以在模板中访问request.get。

然后您可以构建一个过滤器,在构建您正在讨论的链接时返回所需的“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' %}

答案 1 :(得分:0)

也许您尝试使用一些js解决方案。

  1. 只需使用js,构建字典从url获取所有当前属性。

  2. 单击其他属性按钮时,可以在字典中添加或替换属性。

  3. 使用此字典来构成您的网址。

答案 2 :(得分:0)

最后我解决了,尽管解决方案很冗长。


上下文

我想要一个多选过滤器,用户可以在其中过滤产品的品牌。 请注意,如果我每次单击多项选择字段时页面都刷新,就可以了。

主要思想

我通过在视图中为过滤器中每个链接手动添加搜索参数,为多项选择中的每个字段构建了一个不同的链接。每次刷新页面时都会创建新链接,具体取决于选择的多项选择。

代码

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,其中包含查询参数。因此,我通过添加或删除参数为每个链接构建一个不同的URL,具体取决于该链接是否处于活动状态。

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)]