微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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/',# 这里只需要添加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('',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/',# 在include中指定namespace命名空间
    # 不同的前缀指向了相同的urls.py文件,所以只用app应用空间是不够的
    # 需要再指定namespace命名空间,即实例命名空间
    path('cms1/',include('cms.urls',namespace='cms1')),path('cms2/',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)

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐