Django中reverse函数详细使用方法

2019-11-11 11:20:10 最后一行代码 阅读:759

分类: Django

reverse翻译就是“反转”的意思,反向解析url以直接访问其视图方法,该方法可以说非常重要,使用起来也很灵活。让我们来看看怎么使用,都有哪些常用用法。

1、源码

def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
    if urlconf is None:
        urlconf = get_urlconf()
    resolver = get_resolver(urlconf)
    args = args or []
    kwargs = kwargs or {}

    prefix = get_script_prefix()

    if not isinstance(viewname, str):
        view = viewname
    else:
        parts = viewname.split(':')
        parts.reverse()
        view = parts[0]
        path = parts[1:]

        if current_app:
            current_path = current_app.split(':')
            current_path.reverse()
        else:
            current_path = None

        resolved_path = []
        ns_pattern = ''
        ns_converters = {}
        while path:
            ns = path.pop()
            current_ns = current_path.pop() if current_path else None
            # Lookup the name to see if it could be an app identifier.
            try:
                app_list = resolver.app_dict[ns]
                # Yes! Path part matches an app in the current Resolver.
                if current_ns and current_ns in app_list:
                    # If we are reversing for a particular app, use that
                    # namespace.
                    ns = current_ns
                elif ns not in app_list:
                    # The name isn't shared by one of the instances (i.e.,
                    # the default) so pick the first instance as the default.
                    ns = app_list[0]
            except KeyError:
                pass

            if ns != current_ns:
                current_path = None

            try:
                extra, resolver = resolver.namespace_dict[ns]
                resolved_path.append(ns)
                ns_pattern = ns_pattern + extra
                ns_converters.update(resolver.pattern.converters)
            except KeyError as key:
                if resolved_path:
                    raise NoReverseMatch(
                        "%s is not a registered namespace inside '%s'" %
                        (key, ':'.join(resolved_path))
                    )
                else:
                    raise NoReverseMatch("%s is not a registered namespace" % key)
        if ns_pattern:
            resolver = get_ns_resolver(ns_pattern, resolver, tuple(ns_converters.items()))

    return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))

参数说明:

viewname               指定路由别名,也就是路由中name参数。还可以指定命名空间。

args                       向路由传递一个或多个位置参数,传递多个位置参数时需要用列表,如:[xxx, xxx]

kwargs                   向路由传递字典参数,注意这里传递的是个字典对象。

 

函数返回值             url地址

 

二、使用实例

需求:获取登陆页面url地址。

# urls.py
app_name = 'app1'                              # 应用命名空间
urlpatterns = [
    path('', views.index ,name="index"),       # 首页
    path('login/, views.login, name="login")   # 登陆页面
]

# views.py
from django.urls import reverse
def index(request):
    url = reverse('login')       # 通过指定路由别名获取该路由url地址
    url = reverse('app1:login')  # 也可以指定应用命名空间,实例命名空间同理
    pass

 

需求:通过reverse()拼接url查询字符串发送GET请求。

# urls.py
urlpatterns = [
    path("", views.index, name="index"),        # 首页
    path("login", views.login, name="login")    # 登陆页面
]

# views.py
from django.urls import reverse
from django.shortcuts import redirect
def index(request):
    url = reverse('login') + "?data=123"        # 拼接查询字符串
    return redirect(url)                        # 返回/login?data=123

def login(request):
    data = request.GET.get('data')              # 获取GET请求
    print(data)                                 # 打印123
    pass

 

需求:获取第99篇博客详情页url地址。

# urls.py
urlpatterns = [
    path("blog_list/", views.blog_list, name="blog_list"),
    path("detail/<int:blog_id>/", views.detail, name="detail")    # 这里用了转换器来获取指定类型的数据
]

# views.py
from django.urls import reverse
from django.shortcuts import redirect
def blog_list(request):
    url = reverse('detail', args=99)                    # 第一种写法
    url = reverse('detail', kwargs={'blog_id':99})      # 第二种写法,建议使用
    pass

def detail(request, blog_id):
    pass

 

需求:通过<a>标签传递参数,跳转指定博客详情页。

# urls.py
urlpatterns = [
    path("detail/<int:blog_id>/", views.detail, name="detail")    # 这里用了转换器来获取指定类型的数据
]

# views.py
from django.urls import reverse
from django.shortcuts import redirect
def detail(request, blog_id):                             # 因为路由中使用了转换器,所以该形参获取的类型是int
    url = reverse('detail',kwargs={'blog_id': blog_id})   # 动态获取指定博客的详情页url地址
    return redirect(url)                                  # 重定向到指定url

# HTML
<a href="{% url 'detail' blog_id=99 %}">跳转到第99篇博客详情页</a>   # 通过模板标签{% url %}第二个参数向路由中传递参数。如果使用命名空间则{% url 'xxx:detail' blog_id=99 %}


三、总结

1、reverse()在传递参数的时候,路由中必须存在接收的变量,否则报错。

2、reverse()在传递多个位置参数时,使用args参数传递,需要将他们放入列表中,如:args=[xxx, xxx]

3、reverse()在传递多个关键字参数时,使用kwargs参数传递,需要指定字典对象,如:kwargs={'xxx':xxx}

4、reverse()也可以使用命名空间获取对应路由

回复:

快来抢沙发

老板赏瓶水呗
微信 微信 支付宝 支付宝