权限分配之一级菜单保留原搜索条件

如何一直携带 当前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>
原 菜单列表,页面, menu_list.html

视图函数中:

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'  。
需要注意的是, 因为是位置传参, 这两个顺序是不能错的!
menu_list.html


然后最后一个问题了:
我已经将,参数进行处理之后,携带这本次的  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 这个参数,还给我,    不能直接扔了。

 


  

原文地址:https://www.cnblogs.com/chengege/p/10710371.html