您的位置:首页 > 编程语言 > Go语言

Django路由层

2021-06-08 23:16 113 查看 https://www.cnblogs.com/xiaoya

目录
  • 二、URL配置
  • 三、分组
  • 四、路由分发(include)
  • 五、反向解析
  • 六、名称空间
  • 一、MVC和MTV框架

    MVC

    • M 代表模型(Model)
    • V 代表视图(View)
    • C 代表控制器(Controller)

    Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求。

    MTV

    Django 的 MTV 模式本质上和MVC是一样的,也是为 56c 了各组件间保持松耦合关系,只是定义上有些许不同,Django 的MTV分别是值:

    • M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
    • T 代表模板 (Template):负责如何把页面展示给用户(html)。
    • V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。

    除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View 再调用相应的 Model 和 Template

    二、URL配置

    URL配置:它的本质是URL与要为该URL调用的视图函数之间的映射表。

    Django 1.x版本

    url()方法:普通路径和正则路径均可使用,需要自己手动添加正则首位限制符号。

    注意:

    1. urlpatterns中的元素按照书写顺序从上往下逐一匹配,一旦匹配成功则不在继续
    2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
    # urls.py文件
    from django.contrib import admin
    from django.conf.urls import url		# 2.x之后,用 ur
    56c
    l 需要引用
    from app01 import views					# 需要自行导入视图文件 views.py
    
    urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),		# 新增一条
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render
    
    # 新增视图函数
    def index(request):		# request 中包含请求信息
    return render(request, 'index.html')	# 返回的 HTML 页面

    Django 2.x之后版本

    path:用于普通路径,不需要自己手动添加正则首位限制符号,底层已经添加。

    re_path:用于正则路径,需要自己手动添加正则首位限制符号。

    # urls.py文件
    from django.contrib import admin
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),                # 新增-普通路径
    re_path(r'^books/\d{4}/$', views.books)     # 新增-正则路径
    ]
    
    # -------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, HttpResponse	# 导入HttpResponse,用来生成响应信息
    
    def index(request):
    return render(request, 'index.html')		# 返回的 HTML 页面
    
    def books(request):
    return HttpResponse('Hello wo
    ad8
    rld')			# 响应信息

    三、分组

    分组就是需要直接从路径中取出参数,这就用到了正则表达式的分组功能了。

    分组分为两种:无名分组与有名分组

    无名分组

    无名分组按照位置传参,需要一 一对应。

    捕获URL中的值并以位置参数形式传递给视图

    views 中除了request,其他形参的数量要与urls中的分组数量一致。

    # ruls.py文件
    from django.contrib import admin
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    re_path(r'^admin/', admin.site.urls),
    re_path(r'^books/(\d{4})/', views.books),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, HttpResponse
    
    def books(request, year):
    print(year)			# 一个形参代表路径中一个分组的内容,按顺序匹配
    return HttpResponse(f'Hello world {year}')

    有名分组

    语法:

    (?P<组名>正则表达式)

    捕获URL中的值并以关键字参数形式传递给视图。

    有几个有名分组就要有几个关键字参数

    # urls.py文件
    from django.contrib import admin
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    re_path(r'^admin/', admin.site.urls),
    # 匹配成功的分组部分会以关键字参数(name_id = 匹配成功的数字)的形式传给视图函数。
    re_path(r'^books/(?P<name_id>\d{2})/', views.books),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, HttpResponse
    
    # 需要额外增加一个形参,形参名必须为 name_id
    def books(request, name_id):
    return HttpResponse(f'Hello world {name_id}')

    总结:有名分组和无名分组都是为了获取路径中的参数,并传递给视图函数,区别在于无名分组是以位置参数的形式传递,有名分组是以关键字参数的形式传递。

    四、路由分发(include)

    存在的问题:Django项目里有多个app共用一个 urls 容易造成混淆,后期维护不方便。

    解决:使用路由分发(include),让每个app目录都单独拥有自己的 urls。

    步骤:

    1、在各自 app 目录下的创建 urls.py文件, 并对 urls.py 文件和 views.py 文件中写各自的路由和视图函数。 app01下的 urls.py 文件和 views.py 文件

    # urls.py文件
    from django.urls import path, re_path
    from app01 import views		# 导入app01的views
    
    urlpatterns = [
    re_path(r'^index/', views.index),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, HttpResponse
    
    def index(request):
    return HttpResponse('app01页面')

    app02下的 urls.py 文件和 views.py 文件

    # urls.py文件
    from django.urls import path, re_path
    from app02 import views		# 导入app02的views
    
    urlpatterns = [
    re_path(r'^index/', views.index),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, HttpResponse
    
    def index(request):
    return HttpResponse('app02页面')

    2、在项目名称目录下的 urls 文件里面,统一将路径分发给各个 app 目录。

    from django.contrib import admin
    from django.urls import path, re_path, include
    
    # 总路由表
    urlpatterns = [
    re_path(r'^admin/', admin.site.urls),
    
    # 新增两条路由,不能以$结尾
    # include函数就是做分发操作的。
    re_path(r'^app01/', include('app01.urls')),
    re_path(r'^app02/', include('app02.urls')),
    ]

    五、反向解析

    如果路由 层的 url 发生变化,就需要取更改对应的视图层和模板层的 url ,非常麻烦,不便于维护。

    所以可以利用反向解析,当路由层 url 发生变化,在视图层和模块层动态反向解析出更改后的 url ,避免修改操作

    反向解析一般用在模板中的超链接以及视图中的重定向。

    普通反向解析

    登录成功跳转到 index.html 页面:如果 urls.py 文件中的 index 路径有所变化,views.py 文件中不需要更改index路径。

    # urls.py文件
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    # 路径 login/的别名为login_page
    re_path(r'^login/', views.login, name='login_page'),
    # 路径 index/的别名为index_page
    re_path(r'^index/', views.index, name='index_page'),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, reverse, redirect, HttpResponse
    
    def login(request):
    # 当为GET请求时就返回登录页面
    if request.method == 'GET':
    return render(request, 'login.html')
    else:
    # post 请求时,就提取出请求数据。
    use
    ad0
    r = request.POST.get('username')
    pwd = request.POST.get('password')
    if user == 'xiaoyang' and pwd == '123':
    # 会对别名反向解析成路径/index/
    url = reverse('index_page')
    # 然后哦重定向到别名解析的路径
    return redirect(url)
    else:
    return HttpResponse('登录失败')
    
    def index(request):
    return HttpResponse('登录成功!!!')

    登录成功 HTML页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <h1>登录页面</h1>
    
    <!-- 这里的 "{% url 'login_page' %}" 相当于路径/login/-->
    <form action="{% url 'login_page' %}" method="post">
    {% csrf_token %}    <!-- post提交需要做CSRF验证 -->
    用户名:<input type="text" name="username">
    密码:<input type="password" name="password">
    <input type="submit">
    </form>
    
    </body>
    </html>

    分组反向解析

    如果路径存在分组的反向解析使用:

    无名分组:reverse ( "路由别名", arges = ( 符合正则匹配的参数 ) )

    有名分组:reverse ( "路由别名", arges = { "分组名":"符合正则匹配的参数" } )

    # urls.py文件
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    # 无名分组
    re_path(r'^books/(\d{2})/', views.books, name='books_page'),
    # 有名分组
    re_path(r'^years/(?P<year>\d{4})/', views.years, name='years_page'),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, reverse, redirect, HttpResponse
    
    # 有名分组的反向解析
    def years(request, year):
    url = reverse('years_page', kwargs={'year': year})
    
    # HTML 文件中:{% url 'years_page' 'year'=1234 %}
    return HttpResponse(url)
    
    # 无名分组的反向解析
    def books(request, ret):
    url = reverse('books_page', args=(ret,))
    
    # HTML 文件中:{% url 'books_page' 34 %}
    return HttpResponse(url)

    六、名称空间

    Django项目里有多个app,当在不同的 app 目录下的 urls.py 文件中定义了相同的路由别名 name 时,那么在反向解析时则会出现覆盖。

    例如:

    不管输入:http://127.0.0.1:8000/app01/index/ 还是 http://127.0.0.1:8000/app02/index/ 都得到的是 /app02/index/ app02路径的别名覆盖了app01 路径的别名

    app01下的 urls.py 文件和 views.py 文件

    # urls.py文件
    from django.urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    re_path(r'^index/', views.index, name='index_page'),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, reverse, HttpResponse
    
    def index(request):
    url = reverse('index_page')
    return HttpResponse(url)

    app02下的 urls.py 文件和 views.py 文件

    # urls.py文件
    from django.urls import path, re_path
    from app02 import views
    
    urlpatterns = [
    re_path(r'^index/', views.index, name='index_page'),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, reverse, HttpResponse
    
    def index(request):
    url = reverse('index_page')
    return HttpResponse(url)

    项目名称目录下的 urls 文件里面,统一将路径分发给各个 app 目录。

    # urls.py文件
    from django.urls import path, re_path, include
    
    # 总路由表
    urlpatterns = [
    re_path(r'^app01/', include('app01.urls')),
    re_path(r'^app02/', include('app02.urls')),
    ]

    对于这种问题的解决方法就是避免使用相同的别名,如果要使用相同的别名,那就需要将别名放到不同的名称空间中去,这样就避免了即使出现了重复,彼此也不会冲突。

    解决方法:

    格式:

    # 视图中的名称空间的方向解析
    url=reverse('名称空间的名字:待解析的别名')
    # 模板中的名称空间的反向解析
    <a href="{% url '名称空间的名字:待解析的别名'%}">小杨</a>

    1、在 urls.py 路由分发时指定名称空间

    项目名称目录下的 urls 文件里面,统一将路径分发给各个 app 目录。

    # url.py文件
    from django.urls import path, re_path, include
    
    # 总路由表
    urlpatterns = [
    # 给include传递一个元组,第一个是路由分发的地址,第二个是我们自定义的名称空间名字
    re_path(r'^app01/', include(('app01.urls', 'app01'))),
    re_path(r'^app02/', include(('app02.urls', 'app02'))),
    ]

    2、修改每个app下的view.py中视图函数,对不同名称空间的别名做反向解析

    app01下的 urls.py 文件和 views.py 文件

    # urls.py文件
    from django.
    1569
    urls import path, re_path
    from app01 import views
    
    urlpatterns = [
    re_path(r'^index/', views.index, name='index_page'),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, HttpResponse, reverse
    
    def index(request):
    # 解析的是app01下的别名‘index_page’
    url = reverse('app01:index_page')
    return HttpResponse(url)

    app02下的 urls.py 文件和 views.py 文件

    # urls.py文件
    from django.urls import path, re_path
    from app02 import views
    
    urlpatterns = [
    re_path(r'^index', views.index, name='index_page'),
    ]
    
    # ------------------------------------------------------------------
    
    # views.py文件
    from django.shortcuts import render, reverse, HttpResponse
    
    def index(request):
    # 解析的是app02下的别名‘index_page’
    url = reverse('app02:index_page')
    return HttpResponse(url)
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: