1. 路由 router
在实际开发过程中,一个 Django 项目会包含很多的 app,这时如果我们只在主路由里进行配置就会显的杂乱无章,所以通常会在每个 app 里,创建各自的 urls.py
路由模块,然后从根路由出发,奖 app 所属的 url 请求,全部转发到相应的 urls.py
模块中,而这个从主路由转发到各个应用路由的过程叫做路由分发。
(1)路由匹配
1️⃣主路由直接匹配
在主 urls.py
中,直接写
1 2 3 4 5 6 7 8 9 10 11
| from django.contrib import admin from django.urls import path, include from App.views import index
urlpatterns = [ path('admin/', admin.site.urls),
path('index/', index),
]
|
2️⃣子路由匹配
1 2 3 4 5 6 7 8 9 10 11 12
| from django.contrib import admin from django.urls import path, include from App.views import index
urlpatterns = [
path('app/', include('App.urls')), path('app2/', include('App2.urls')), ]
|
1
| <a href="/user/userlist/">用户列表</a>
|
(2)使用子路由 + 命名空间
在实际应用中,Django 中可能存在多个应用程序,每个应用程序都有可能有自己的路由模块。为了防止路由冲突,Django 提供了命名空间(namespace)的概念。命名空间是一种奖路由命名为层次结构的方式,使得在查询路由时可以限定在命名空间内。(如果使用了命名空间的这种写法,则在之后的视图函数 / 模板中都要使用命名空间的写法,否则会报错)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from django.contrib import admin from django.urls import path, include from App.views import index
urlpatterns = [ path('admin/', admin.site.urls),
path('user/', include(('App2.urls', 'App2'), namespace='App2')),
path('user/', include(('App.urls', 'App'), namespace='App')), ]
|
(3)反向解析
在 Django 框架中,正向解析是指根据 URL 配置文件中的 URL 模式来匹配用户请求的 URL,并调用相应的视图函数。这是 Django 处理 HTTP 请求的标准流程。
当用户在浏览器中输入一个 URL 并发送请求时,Django 会按照以下步骤进行正向解析:
1️⃣Django 接收到请求,并从请求中提取出 URL 路径。
2️⃣Django 遍历 URL 配置文件中的 URL 模式列表,尝试找到与请求 URL 匹配的模式。
3️⃣如果找到匹配的模式,Django 会调用与该模式关联的视图函数,并将请求传递给该视图函数进行处理。
4️⃣视图函数处理请求,并返回一个 HTTP 响应给用户。
反向解析是 Django 框架中的一个特性,它允许你在代码中使用视图函数或 URL 模式的名称来动态生成 URL,而不是直接硬编码 URL 字符串。这样做的好处是,当你需要修改 URL 模式时,只需要在 URL 配置文件中进行修改,而不需要在整个项目中查找和替换所有硬编码的 URL 字符串。
反向解析的流程如下:
1️⃣定义 URL 模式
在 Django 的 URL 配置文件中,你需要为每个视图函数或 URL 模式定义一个名称。例如:
1 2 3 4 5 6
| from django.urls import path from . import views
urlpatterns = [ path('userlist/', views.userlist, name='userlist'), ]
|
2️⃣在模板中使用反向解析
- 在模板中,你可以使用
{% url %}
模板标签来生成 URL。例如:
1
| <a href="{% url 'userlist' %}">用户列表</a>
|
这里的 userlist
就是之前定义的 URL 名称。
主路由 urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from django.contrib import admin from django.urls import path, include from App.views import index
urlpatterns = [ path('admin/', admin.site.urls),
path('index/', index),
path('app2/', include(('App2.urls', 'App2'), namespace='App2')),
path('app/', include(('App.urls', 'App'), namespace='App')), ]
|
templates/index.html
1 2 3 4 5 6
| <h2>带命名空间的反向解析</h2> {# App:userlist 为 namespace : name 的值,也就是 命名空间:} <a href="{% url 'App:userlist' %}">用户列表</a> <hr> <a href="{% url 'App2:userlist2' %}">用户列表2</a>
|
3️⃣在视图中的反向解析 (带命名空间)
1 2 3 4
| def user_reverse(request): url = reverse('App:userlist') return redirect(url)
|
4️⃣在其他地方的反向解析
除了模板和视图,你还可以在其他地方使用反向解析,比如在表单的 action 属性中,或者在 JavaScript 代码中。
后续学习了,在来这里总结。
总结来说,反向解析的流程是:先在 URL 配置文件中为 URL 模式定义名称,然后在模板或视图中使用这些名称来动态生成 URL。这样做可以提高代码的可维护性和灵活性。
(4)路由传参
1️⃣单一参数:
1 2 3 4 5 6 7
| path('index/', index) path('detail/<int:id>/', detail)
path('index/', index, name='index') path('detail/<int:id>', detail, name='detail')
|
views.py
1 2 3 4
| def user_detail(request, pk): print(pk) user = UserModel.objects.get(pk=pk) return render(request, 'user_detail.html', {'user': user})
|
2️⃣多参数:
1 2 3 4 5
| path('userab/<int:a>/<int:b>', user_ab, name='userab'),
re_path(r'^userab2/(?P<a>\d+)/(?P<b>\d+)$', user_ab, name='userab2'),
|
views.py
1 2
| def user_ab(request, a, b): return HttpResponse('a={}, b={}'.format(a, b))
|
(5)重定向
在 Django 中,重定向是一种常见的操作,通常用于在处理完某个请求后,将用户引导到另一个页面。Django 提供了多种方式来实现重定向,以下是一些常见的方法:
1️⃣使用 redirect
函数:
views.py
1 2 3
| def user_redirect(request): return redirect('/app/userlist/')
|
- redirect 函数接受一个 URL 作为参数,并返回一个 HTTP 重定向响应。
- 你可以传递一个完整的 URL,或者一个视图函数的名称,Django 会自动解析并生成正确的重定向 URL。
2️⃣使用 reverse
函数生成 URL
reverse
函数用于根据视图函数的名称生成 URL
, 这在你需要动态生成重定向 URL
时非常有用。
App/urls.py
1 2 3 4 5
| path('userlist/', user_list, name='userlist'), path('userreverse/', user_reverse, name='userreverse'),
|
views.py
1 2 3 4
| def user_reverse(request): url = reverse('App:userlist') return redirect(url)
|
3️⃣“位置参数”
views.py
1 2 3 4
| def user_reverse2(request): url = reverse('App:userdetail', args=(1,)) return redirect(url)
|
4️⃣“关键字参数”
views.py
1 2 3 4
| def user_reverse3(request): url = reverse('App:userdetail', kwargs={'pk': 1}) return redirect(url)
|
2. 关键代码
(1)主路由 urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from django.contrib import admin from django.urls import path, include from App.views import index
urlpatterns = [ path('admin/', admin.site.urls),
path('index/', index),
path('app2/', include(('App2.urls', 'App2'), namespace='App2')),
path('app/', include(('App.urls', 'App'), namespace='App')), ]
|
(2)子路由 1App/urls.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| from django.contrib.auth.views import LoginView from django.urls import path, re_path from App.views import *
urlpatterns = [ path('userlist/', user_list, name='userlist'),
path('userdetail/<int:pk>/', user_detail, name='userdetail'),
path('userab/<int:a>/<int:b>', user_ab, name='userab'),
re_path(r'^userab2/(?P<a>\d+)/(?P<b>\d+)$', user_ab, name='userab2'),
path('userredirect/', user_redirect, name='userredirect'),
path('userreverse/', user_reverse, name='userreverse'),
path('userreverse2/', user_reverse2, name='userreverse2'), path('userreverse3/', user_reverse3, name='userreverse3'), ]
|
(3)子路由 2App2/urls.py
1 2 3 4 5 6
| from django.urls import path from App2.views import *
urlpatterns = [ path('userlist/', user_list, name='userlist2'), ]
|
(4)App/views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| from django.http import HttpResponse from django.shortcuts import render, redirect, reverse
from App.models import *
def index(request): return render(request, 'index.html')
def user_list(request): users = UserModel.objects.all() return render(request, 'user_list.html', {'users': users})
def user_detail(request, pk): print(pk) user = UserModel.objects.get(pk=pk) return render(request, 'user_detail.html', {'user': user})
def user_ab(request, a, b): return HttpResponse('a={}, b={}'.format(a, b))
def user_redirect(request): return redirect('/app/userlist/')
def user_reverse(request): url = reverse('App:userlist') return redirect(url)
def user_reverse2(request): url = reverse('App:userdetail', args=(1,)) return redirect(url)
def user_reverse3(request): url = reverse('App:userdetail', kwargs={'pk': 1}) return redirect(url)
|
(5)App2/views.py
1 2 3 4 5 6
| from django.shortcuts import render
def user_list(request): return render(request, 'user_list2.html')
|
(6)Templates/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> {#测试注释#} <h2>1.正常的路由跳转</h2> <hr> {#这里是直接访问了视图函数,通过视图函数做相应的跳转#} <a href="/app/userlist/">用户列表</a>
<hr>
<h2>反向解析</h2> {# userlist 为 path路由的 name 值#} {#<a href="{% url 'userlist' %}">用户列表</a>#} <hr>
<h2>带命名空间的反向解析</h2> {# App:userlist 为 namespace:name 值#} <a href="{% url 'App:userlist' %}">用户列表</a> <hr> <a href="{% url 'App2:userlist2' %}">用户列表2</a>
<h2>重定向redirect</h2> {# 重定向到用户列表页面#} <a href="{% url 'App:userredirect' %}">重定向</a> <hr> <h2>重定向reverse+redirect</h2> <a href="{% url 'App:userreverse' %}">重定向2</a> <hr> <h2>重定向带+“位置参数”</h2> <a href="{% url 'App:userreverse2' %}">重定向带位置参数</a> <hr> <h2>重定向带+“关键字参数”</h2> <a href="{% url 'App:userreverse3' %}">重定向带关键字参数</a>
</body> </html>
|
(7)Templates/user_list.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户列表</title> </head> <body> <h2>用户列表</h2> <hr>
<ul> {% for user in users %} <li> <a href="{% url 'App:userdetail' user.id %}">{{ user.username }}</a> </li> {% endfor %} </ul>
</body> </html>
|
(8)Templates/user_list2
1 2 3 4 5 6 7 8 9 10
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户列表 2</title> </head> <body> <h2>用户列表 2</h2> </body> </html>
|
(9)Templates/user_detail.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户详情</title> </head> <body>
<ul> <li> {{ user.username }} -- {{ user.age }} </li> </ul>
</body> </html>
|
(10)App/models.py
1 2 3 4 5 6 7
| from django.db import models
class UserModel(models.Model): username = models.CharField(max_length=100) age = models.PositiveIntegerField(default=18)
|
3. 相关参考
https://www.bilibili.com/video/BV1W34y1c7Rn?spm_id_from=333.788.videopod.episodes&vd_source=fd555860cd7cf9b09d9279e5deaabb9d&p=21