如何使用Django模板系统构建带多查询参数的URL
Django 多查询参数URL构建方案
你现在遇到的核心问题不是字符串拼接过滤器的问题,是Django模板本身的机制限制:
- 首先
{% with %}标签的赋值只在标签包裹的块内部生效,你在循环里每次开的{% with %}{% endwith %}块,出了块之后赋的值直接就丢了,根本不会累计你拼的字符串 - 其次你把变量命名为
request,会直接覆盖模板默认注入的请求上下文对象,属于容易出bug的坏命名习惯 - 最后就算你绕开作用域问题,手动拼查询字符串很容易出现末尾多余
&、特殊字符没编码的问题,稳定性很差。
你贴的原有问题代码如下:
{% url 'service-ticket/new' as request %} {% with request|add:"?" as request %} {% endwith %} {% for entry in object.items.all %} {% with request|add:"spareparts="|add_string:entry.item.id|add:"&" as request %} {% endwith %} {% endfor %} <a class="btn-add float-right" href={{ request }} role="button"> THIS SHOW HAVE ALL </a>
推荐实现:逻辑移到视图层(最稳妥)
模板本身的定位就是做渲染输出,不适合写累计拼接这类逻辑,直接在视图里把URL拼完传给模板是最省事、最不容易出问题的方案,Django本身也自带了查询参数处理的工具,不用手动拼字符串:
from django.urls import reverse from django.http import QueryDict def detail_view(request, pk): # 拿到你要关联的对象 service_obj = ServiceModel.objects.get(pk=pk) # 先拿到基础路径 base_path = reverse('service-ticket/new') # 初始化可变的查询参数对象 qd = QueryDict(mutable=True) # 直接给同名参数传列表,自动处理成多值参数格式 qd.setlist('spareparts', [entry.item.id for entry in service_obj.items.all()]) # 拼出完整URL full_ticket_url = f"{base_path}?{qd.urlencode()}" return render(request, 'detail.html', { 'object': service_obj, 'ticket_url': full_ticket_url })
模板里直接用就行,不需要写循环拼字符串:
<a class="btn-add float-right" href="{{ ticket_url }}" role="button"> THIS SHOW HAVE ALL </a>
这种写法自动处理URL编码、参数格式,不会出现多余符号,后续要加其他查询参数也只需要在视图里改,维护成本很低。
如果你多个模板都需要生成这类带查询参数的URL,写一个简单的自定义模板标签复用逻辑就行,不用每个视图重复写。
不推荐:纯模板层实现
Django原生模板没有提供跨作用域修改变量的能力,纯靠原生标签根本实现不了循环累计拼接字符串的需求,必须额外自定义capture类的标签把循环里的内容累计存下来,再配合自定义过滤器拼查询参数,写法冗余还难维护,完全没必要。
内容的提问来源于stack exchange,提问作者Pedro Magno Müller
相关产品推荐
相关产品推荐

