• Django笔记:URL映射


    本文主要记了一些Django中URL映射相关的知识点,包括URL映射关系配置、URL传参、URL反转等。

    一、URL映射关系配置

    URL映射关系默认是配置在主app下urls.py中的urlpatterns列表中,如果想要自己指定配置映射关系所在文件,只需要修改主app中settings.py文件中的ROOT_URLCONF配置项即可,但是urlpatterns这个变量是固定的,无法修改,所以修改ROOT_URLCONF配置项之后,Django就会到你指定的文件中查找urlpatterns变量,并根据这个列表中的映射关系来进行URL的映射。
    urlpatterns列表中的元素是一个经过pathre_path函数包装后的结果,这两个函数都在django.urls中,直接导入使用即可。这两个函数的用法都是相似的,不同之处在于,re_pathroute参数(即URL)需要使用正则表达式,如果对URL没有特殊要求的话,建议尽量使用path就可以了。
    path函数常见用法有两种:

    • 一种是直接传入URL字符串和对应视图函数两个参数即可,例如path('article/page/2/', views.page_detail),第一个route参数为URL字符串,第二个view参数为URL对应的视图函数。通常情况下两个参数已经够用了,但是如果想要给这个URL命令,以便用于URL的反转,可以指定name参数。
    • 另一种是指定子app的URL前缀以及使用include函数包装的子appurls.py路径,例如path('articel/', include('article.urls')),第一个route参数只需要指定子app的URL前缀,不需要给出完整的URL字符串,第二个view参数为通过django.urls.include包装后的子appurls.py路径。这种用法涉及到URL的分层管理,可以参考后面“URL分层管理”小节。

    二、URL传参

    1、URL查询字符串

    URL中查询字符串的参数直接使用视图函数的第一个参数request.GET进行获取即可,查询字符串通常是通过GET方式发送的请求,所以查询字符串的信息可以在request.GET中得到,而这个变量是一个类似字典的数据结构,直接使用它的get方法进行获取即可。(POST提交的请求信息在request.POST中,也可以通过get方法获取表单中name属性对应的值)
    示例:访问http://127.0.0.1:8000/book/author/?id=3,对应的视图函数如下

    def author_detail(request):
        author_id = request.GET.get('id')
        text = '作者的ID是:{}'.format(author_id)
        return HttpResponse(text)
    

    2、URL参数传递

    如果想要URL字符串中的某部分变成参数传递给视图函数,可以在指定URL字符串时使用尖括号<param_name>将对应参数括起来,并在视图函数中定义相同名称的参数即可。当然,也可以在URL字符串中定义多个参数,只需要在视图函数中按顺序定义同样的参数来接收即可。
    注:可以给视图函数的参数指定默认值,访问时如果URL中没有传入该参数则会使用该参数的默认值。

    """视图函数代码"""
    from django.http import HttpResponse
    
    
    def book(request):
        return HttpResponse("图书首页!")
    
    
    # 注意此处的book_id必须与URL中的参数<book_id>是相同的
    def book_detail(request, book_id):
        text = "你获取的图书id是:{}".format(book_id)
        return HttpResponse(text)
    
    """URL映射关系配置代码"""
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('book/', book),
        path('book/detail/<book_id>/', book_detail)
    ]
    

    注:使用re_path时,传参使用正则表达式的分组命名方式,即(?P<param_name>),这个参数名与视图函数的参数名也是一一对应的。

    3、使用URL类型转换器指定参数类型

    URL字符串中传递给视图函数的参数默认都是字符串类型的,即使用的是默认的URL类型转换器str,如果想要给参数指定为别的类型,如int类型,则需要使用形如<int:book_id>来进行参数类型指定。注意,如果指定了URL类型,那么在视图函数中拿到的该参数也是对应的数据类型,例如指定了参数为int类型,不仅URL字符串中该部分必须满足int类型要求,而且视图函数中该参数拿到后也是Python中对应的int类型。
    Django中有一些内置的URL类型转换器,都在from django.urls import converters中,可自行查看,常用的有以下几种:

    • int:必须是0到9之间的一个或多个数字。
    • str:除了斜杠/之外的一个或多个任意字符。(也是默认的参数类型)
    • uuid:一个uuid字符串,可以使用Python内置库方法来生成import uuid;uuid.uuid4()
    • slug:满足正则[-a-zA-Z0-9_]+的所有字符串。
    • path:一个或多个任意字符(斜杠/也可以)。

    4、自定义URL类型转换器

    自定义URL类型转换器其实也是根据内置的转换器写法来进行自定义的,可以参考from django.urls import converters中内置转换器的源码,一个自定义的url类型转换器通常分为三部分:regex正则表达式(转换规则)、to_python函数(将url中的参数处理之后再传入视图函数)和to_url函数(将参数处理之后再拼接到url之中)。定义好转换器之后,需要使用from django.urls import register_converter将转换器注册到Django中。
    示例代码如下:

    """直接定义在urls.py中"""
    from django.urls import path
    from . import views
    from django.urls import register_converter
    
    
    # 自定义URL类型转换器:将URL中类似python+django+flask的字符串
    # 转换为以+分隔的列表传入视图函数中,反转为URL时再以+拼接到URL中
    class CategoryConverter:
        regex = r'w+|w+(+w+)+'
    
        def to_python(self, value):
            # 此方法是将url中的参数处理之后再传入对应的视图函数中
            # value:python+django+flask
            return value.split('+')
    
        def to_url(self, value):
            # 此方法是将在reverse反转时给url传入的参数处理之后再放入url中,形成最终的url
            # value:['python', 'django', 'flask']
            return '+'.join(value)
    
    
    # 注册自定义的转换器
    register_converter(CategoryConverter, 'cate')
    
    urlpatterns = [
        path('', views.article),
        # 使用自定义的转换器
        path('list/<cate:categories>/', views.article_list, name='list')
    ]
    
    """views.py"""
    def article_list(request, categories):
        # 如果访问:http://127.0.0.1:8000/article/list/python+django+flask/
        # 打印结果为:/article/list/python+django+flask/
        print(reverse('list', kwargs={'categories': categories}))
        text = '文章分类是:{}'.format(categories)
        return HttpResponse(text)
    

    注:url转换器定义的文件一定要在运行时得到执行,不然无法进行注册,可以放在urls.py中,也可以将定义转换器的文件在包的__init__.py文件中进行导入。

    三、URL分层管理

    当新建的app较多时,不宜将所有的URL映射都放在主app(该app通常与项目同名)的urls.py文件中,就像app下的views.pymodels.py等文件(使用命令窗口的命令创建app时,会自动生成这些文件),用专门的文件来管理各自的功能,推荐在app下新建一个urls.py文件,用来专门管理当前app的所有URL映射关系,这样也方便开发人员的维护和管理。
    URL的分层管理需要注意以下两点:

    • 在子app下新建一个urls.py(文件名称可以自己取,但是通常就命名为urls.py即可,方便辨认),然后在里面同样定义一个urlpatterns变量。注意,这个urlpatterns中的URL字符串不用再添加子app对应的URL前缀了。
    • 在主app的urls.pyurlpatterns变量中添加一个URL映射,第一个参数为子app的URL前缀,第二个参数为from django.urls import include包装的子app对应的urls.py文件路径(此路径为相对于项目根目录的相对路径)。
    """主app的urls.py文件内容"""
    from django.contrib import admin
    from django.urls import path, include
    
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        # 这里只需要添加app的url前缀和对应urlpattterns变量所在文件的路径即可
        path('book/', include('book.urls'))
    ]
    
    """子app“book”目录中的urls.py文件内容"""
    from django.urls import path
    from .views import book, book_detail
    
    
    # 这里不用再添加app的url前缀了
    urlpatterns = [
        path('', book),
        path('detail/<book_id>/', book_detail)
    ]
    

    四、URL反转

    URL反转表示根据一个名称就可以得到对应的完整URL字符串,而不用自己每次手动编写完整的URL,如果项目中许多地方都会用到某个URL,就可以考虑使用URL反转了,URL反转需要用到from django.shortcuts import reverse,基本用法为:使用形如reverse(url_name)即可得到对应的URL。

    1、URL命名

    想要给URL命名,在配置URL映射关系时,给path函数指定name参数即可,然后使用reverse(url_name)函数反转就可以得到对应名称的URL了。

    """配置URL映射关系"""
    from django.urls import path
    from hello_world import views
    
    urlpatterns = [
        # 使用name参数给当前URL指定名称
        path('index/', views.index, name='index')
    ]
    
    """视图函数定义"""
    from django.shortcuts import render, reverse
    
    
    def index(request):
        # 获取名称为index的URL,打印结果为:/index/
        print(reverse('index'))
        return render(request, 'index.html')
    

    2、app应用命名空间和实例命名空间

    配置app应用命名空间是为了规避产生同名URL的情况,app应用命令空间的配置是直接在对应app目录的urls.py中定义一个app_name=xxx的变量即可,反转时加上对应的app_name即可,如reverse('app_name:url_name')

    from django.urls import path
    from . import views
    
    # 配置app应用命令空间
    app_name = 'front'
    
    urlpatterns = [
        path('', views.index),
        # 给URL指定名称
        path('login/', views.login, name='login'),
    ]
    
    from django.http import HttpResponse
    from django.shortcuts import redirect, reverse
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('前台 首页!')
        else:
            # 反转时使用“app应用命名空间:url名称”的格式
            return redirect(reverse('front:login'))
    

    使用实例命名空间是为了规避不同的URL映射到了相同的urls.py中,即不同的实例映射到了同一个app上,此时反转得到的URL可能就不是我们想要的了。实例命名空间配置是在主app中配置子app的URL前缀时的include中指定其namespace参数,然后再使用request.resolver_match.namespace获取当前实例命名空间即可,此时就不再使用应用命名空间了(虽然配置了)。注意,指定实例命名空间时必须同时指定应用命名空间,单独指定实例命名空间是不可以的,程序会报错。

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        # 在include中指定namespace命名空间
        # 不同的前缀指向了相同的urls.py文件,所以只用app应用空间是不够的
        # 需要再指定namespace命名空间,即实例命名空间
        path('cms1/', include('cms.urls', namespace='cms1')),
        path('cms2/', include('cms.urls', namespace='cms2')),
        path('', include('front.urls'))
    ]
    
    from django.http import HttpResponse
    from django.shortcuts import redirect, reverse
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('cms 首页!')
        else:
            # 获取当前所处的实例命名空间
            current_namespace = request.resolver_match.namespace
            return redirect(reverse('{}:login'.format(current_namespace)))
    

    五、其他函数

    1、django.urls.include

    include有三种用法:include(module, namespace=None)include((pattern_list, app_namespace), namespace=Noneinclude(pattern_list),它们的参数使用如下:

    • module:子URL的模块字符串(即对应app的urls.py文件路径)。
    • namespace:实例命名空间。需要注意的是,指定实例命名空间时,需要同时指定对应的app应用命名空间(在对应app的urls.py中配置变量app_name)。
    • pattern_list:一个子URL的模块字符串或者path对象的列表,后者相当于是在path的第一个参数指定了子app的URL前缀,如果这个子app下有多个URL,就可以直接放在这个pattern_list列表中。
    • app_namespace:应用命名空间。注意,应用命名空间既可以在include中指定,也可以通过在子app的urls.py中配置app_name的方式来指定。
    • namespace:实例命名空间。

    2、django.shortcuts.reverse

    reverse用于url的反转,通常只需要在path中指定name参数即可(必要的时候也可以指定app应用命名空间或实例命名空间)。如果url中含有参数,则需要在使用reverse时传入kwargs参数,以字典的形式将参数传入。
    注:如果是查询字符串的参数,则需要reverse反转之后自己手动进行拼接url字符串。

    """视图函数"""
    from django.http import HttpResponse
    from django.shortcuts import reverse, redirect
    
    
    def index(request):
        username = request.GET.get('username')
        if username:
            return HttpResponse('首页')
        else:
            # detail对应的url映射为:path('detail/<article_id>/', article_detail, name='detail'),
            detail_url = reverse('detail', kwargs={'article_id': 333})
            # 如果需要传入查询字符串,则需要自己手动进行拼接,如:detail_url += '?username=xxx'
            return redirect(detail_url)
    
    
    def article_detail(request, article_id):
        text = '文章的id是:{}'.format(article_id)
        return HttpResponse(text)
    

    注:本文为学习笔记,发现错误欢迎指出。

  • 相关阅读:
    codeforces 869E. The Untended Antiquity(二维树状数组,随机化)
    bzoj 3083: 遥远的国度(树上换根操作,树剖+询问整个子树)
    hdu 5534 Partial Tree(dp+降唯,好题)
    AtCoder Regular Contest 075 E
    hihocoder 1387 A Research on "The Hundred Family Surnames"(树,lca,求同一颜色的直径)
    hdu 5458 Stability(生成树,树链剖分,好题)
    推荐一套个人ui组件库
    回望2019,期盼2020
    如何从产品的角度对待自己的博客
    致一名迷茫的我
  • 原文地址:https://www.cnblogs.com/guyuyun/p/13791652.html
Copyright © 2020-2023  润新知