如何一直携带 当前GET请求中, ?mid=1&age=2&name=alex
先看一看问题的产生:
1.我的菜单列表页面,当我点击,某一个菜单选项时。会发送一个GET请求,并且将当前这个菜单的 id 发送到服务端。
服务端进行页面渲染时, 会为这个菜单添加一个,calss="active":
看代码:
<tr class="{% if menu_id == menu.pk|safe %}active{% endif %}"> <th><a href="?mid={{ menu.pk }}">{{ menu.title }}</a></th> <td><i class="fa {{ menu.icon }}" aria-hidden="true"></i></td> <td> <a style="color: #333333;" href="{% url 'rbac:menu_edit' pk=menu.pk %}"> <i class="fa fa-edit" aria-hidden="true"></i></a> <a style="color: #d9534f;" href="{% url 'rbac:menu_del' pk=menu.pk %}"><i class="fa fa-trash-o"></i></a> </td> </tr>
视图函数中:
def menu_list(request):
'''
菜单和权限列表
:param request:
:return:
'''
# menu_id = int(request.GET.get("mid")) # 前端判断时,需要一个int类型,而不是str类型。
menu_id = request.GET.get("mid") # 或者在前端进行转换,将数字转换成,字符串
menu_list = models.Menu.objects.all()
return render(request, "rbac/menu_list.html", locals())
def menu_add(request):
'''
添加页面
:param request:
:return:
'''
if request.method == "POST":
forms = MenuForm(request.POST)
if forms.is_valid():
forms.save()
return redirect("rbac:menu_list") # 这里需要做更改
else:
return render(request, "rbac/change.html", {"forms": forms})
forms = MenuForm()
return render(request, "rbac/change.html", {"forms": forms})
视图函数中,无需更改。 我需要做的就是,在模板中,生成url的时候,要做一些改动。
比如:
我当前的菜单列表url http://127.0.0.1:8000/rbac/menu/list/?mid=1
进入添加菜单url : http://127.0.0.1:8000/rbac/menu/add/?_filter=mid%3D1
这就是我想要的效果:
当前菜单列表,有 mid=1 的参数。 而我想做的就是,进入下一个页面的时候, 将mid=1 这个参数给携带上。
但是又不能够直接就 拼接在后面, 因为如果我的添加页面,在提交数据的时候 也有一个参数是 mid=1 那么, 服务端 就不能够进行处理。
所以, 我将 mid=1 进行转义打包成 _filter=mid%3D1。 单独使用一个变量来接收我想要的真实数据。
来看看如何实现:
1.要想实现的话, 就要在服务端进行渲染页面时。 在对url 反向解析时,进行处理。
原来我是使用 <a href="{% url 'rbac:menu_add' %}">添加菜单</a>。 这样的做法,只能够解析出这个url的地址,但 是却不能够, 携带上我的 mid=1 这个参数。
他解析出来是 http://127.0.0.1:8000/rbac/menu/add/ 这个样子的。
但是我需要的是 http://127.0.0.1:8000/rbac/menu/add/?_filter=mid%3D1 这个样子的。
2. so 定义一个模板语法吧:
这个模板语法需要的参数, 一定要 request 因为我需要从request对象中, 取得当前GET请求中携带的参数 mid=1。
然后是 'rbac:menu_add' 我需要这个名字,进行 reverse() 反向解析出。我要进入的这个url。 最后还有一点, 是针对 带有正则的 url 。 针对这种 url 在反向解析的时候, 必须要提供给reverse() 方法。这个参数。
比如:re_path(r"^menu/edit/(?P<pk>\d+)/$", menu.menu_edit, name="menu_edit"),
在反向解析的时候 就需要 reverse("rbac:menu_edit", 12) 后面根的是什么,取决于正则是怎么写的。
然后有一点要注意的是, 如果是 /(?P<pk>\d+)/ 这就是有名分组, 传参数时就是, 关键字传参。
如果是 /(\d+)/ 这就是无名分组, 传参数时就是, 位置参数传参。
基于以上的理由,进行, 这个自定义模板的编写:
def memory_url(request, name, *args, **kwargs): ''' 生成带有原搜索条件的url (?mid=1&age=20) (替代原模板中的url) :param request: # 从request中获取,当前请求的所有参数 :param name: # 帮助反向解析,生成url 'rbac:menu_list' :return: ''' basic_url = reverse(name, args=args, kwargs=kwargs) # basic_url = reverse(name, kwargs="", args="") # reverse中使用kwargs传参,或者使用args传参, 取决于在url路由分发的阶段, 正则表达式 是关键字传参还是位置传参 # 当前GET请求的url中无参数,携带。直接返回 反向解析的,地址 if not request.GET: return basic_url # 当前GET请求的url中有参数,携带。 那么就需要将,这次请求的url 中的参数。进行打包,传给下一次的url query_dict = QueryDict(mutable=True) # 使用django自带的Query_Dict 进行参数的打包。 query_dict["_filter"] = request.GET.urlencode() # 获取到本次GET请求携带的数据mid=2 。 并交给QueryDict进行转义打包 # query_dict.urlencode() # 这里就会使自动转义之后的字符串 _filter=mid%3D1 return "%s?%s" % (basic_url, query_dict.urlencode())
reverse(name, args=args, kwargs=kwargs) 先对,基础的路由地址url 进行解析。
判断,当前请求中, 是否有参数携带。 request.GET 如果是 None 的话, 就说明没有参数携带, 也就不需要进行把参数携带到下一个路由当中了。
使用Django自带的QueryDict, 来打包我们的参数。 理由上述已经讲过。
如果有参数携带的话, 最终返回的, 就是携带了参数的 一条完整的 url
模板中的使用:
<div class="panel-heading"><i class="fa fa-book" aria-hidden="true"></i> 一级菜单 <a href="{% memory_url request 'rbac:menu_add' %}" class="right btn btn-success btn-xs" style="padding: 2px 8px;margin: -3px;"> <i class="fa fa-plus-circle" aria-hidden="true"></i> 新建 </a> </div> 模板中需要填入的参数,只有 request 和 'rbac:menu_add' 。 需要注意的是, 因为是位置传参, 这两个顺序是不能错的!
然后最后一个问题了:
我已经将,参数进行处理之后,携带这本次的 mid=1 进入到了。下一次的url中。
那么, 往回跳转的时候呢?
看代码:
def memory_reverse(request, name, *args, **kwargs):
'''
反向生成url。
1.在url获取原来的搜索条件, 如_filter之后的值
2.reverse反向解析原来的url 如:/menu/list/
3.进行拼接:/menu/list/?_filter=mid%3D2
示例:
http://127.0.0.1:8000/rbac/menu/add/?_filter=mid%3D2
解析之后:
http://127.0.0.1:8000/rbac/menu/list/?mid=2
:param request:
:param name: # url的别名
:param args: # url中正则分组的位置参数
:param kwargs: #url中正则分组的关键字参数
:return:
'''
url = reverse(name, args=args, kwargs=kwargs)
origin_params = request.GET.get("_filter")
if origin_params:
url = "%s?%s" % (url, origin_params)
return url
我们知道,在视图中跳转使用的是: redirect()
比如 我在添加成功菜单成功之后的 视图函数是这样写的:
def menu_add(request):
'''
添加页面
:param request:
:return:
'''
if request.method == "POST":
forms = MenuForm(request.POST)
if forms.is_valid():
forms.save()
return redirect(reverse("rbac:menu_list"))
else:
return render(request, "rbac/change.html", {"forms": forms})
forms = MenuForm()
return render(request, "rbac/change.html", {"forms": forms})
看代码,可以看出。 也没什么不对。 但是如果单纯的这样写, 我自己的反向解析函数 momory_reverse() 不就白写了嘛!
而且最重要的, 我想要的 ../?_filter=mid%3D1 这个 问号,后面的参数, 没有给我带过来。
so:还是,使用。我的这个反向解析函数:
def menu_add(request):
'''
添加页面
:param request:
:return:
'''
if request.method == "POST":
forms = MenuForm(request.POST)
if forms.is_valid():
forms.save()
return redirect(memory_reverse(request, "rbac:menu_list"))
else:
return render(request, "rbac/change.html", {"forms": forms})
forms = MenuForm()
return render(request, "rbac/change.html", {"forms": forms})
让,我跳转向的, menu_list 的url 能够携带上。 进入添加页面之前时,我在 menu_list 页面 url中所有的 mid=1 这个参数。
可能有些,难以理解。 不过举个例子就是:
我在 菜单列表页面时,我的参数中有一个 mid=1
然后 你带着这个 mid=1 到添加页面,逛了一圈。
然后回来的时候, 你得把这个 mid=1 这个参数,还给我, 不能直接扔了。