当前位置: 首页 > news >正文

Django路由学习笔记

1. Django路由作用

连接视图和用户请求的重要桥梁。

2. Django路由类型

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

普通路径:

# 无动态段
urlpatterns = [path('index/', views.indexUsers, name='user-detail'),
]# 有动态段,无转换器
urlpatterns = [path('articles/<year>/<month>/', views.article_archive, name='article-archive'),
]# 视图中可以获取参数 year, mouth
def article_detail(request, year, month):# 这里可以根据year, month, day和title来进行数据库查询或其他操作pass# 有动态段,有转换器
urlpatterns = [path('articles/<int:year>/<str:month>/', views.article_archive, name='article-archive'),
]# 视图中可以获取参数 year, mouth
def article_detail(request, year, month):# 这里可以根据year, month, day和title来进行数据库查询或其他操作pass

正则路径:

# 无命名参数
urlpatterns = [re_path("^index5/([0-9]{4})/([0-9]{2})/$", views.Regular.as_view()),
]class Regular(View):def get(self, request, year, month):print(year, month)return HttpResponse('路由无名参数')# 命名参数
urlpatterns = [re_path("^index6/(?P<year1>[0-9]{4})/(?P<month>[0-9]{2})/$", views.Regular6.as_view()),
]# 注意参数要和一致
class Regular6(View):def get(self, request, year1, month):print(year1, month)return HttpResponse('路由有名参数')

3.反向解析URL

反向解析是指通过视图名称和参数来动态生成URL的过程。

from django.urls import reverse
def some_view(request):# ...url = reverse('my_view_name', args=[1, 2, 3])# 现在变量url包含'/path/to/my_view_name/1/2/3/'

reverse() 函数:

  • Python代码(视图、模型方法)中使用。
  • 根据 URL 的名称name 参数)和可选的参数kwargs)生成实际的 URL 字符串。
  • 用法:reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)

{% url %} 模板标签:

  • Django模板中使用。
  • 功能与 reverse() 相同,但在模板语法中。
  • 用法:{% url 'view_name' arg1 arg2 kwarg1=value1 %}

命名空间 (app_name):

  • 使用 app_name 可以避免不同应用间 URL 名称冲突。
  • 在 reverse() 或 {% url %} 中,需要使用 'app_name:url_name' 的格式。
# myapp/urls.py
urlpatterns = [# path('', views.index, name='index'), # 根路径path('articles/', views.index, name='index'), # 更清晰的路径path('articles/<int:article_id>/', views.article_detail, name='article_detail'),path('articles/create/', views.create_article, name='create_article'),
]
# myapp/views.pydef index(request):"""显示所有文章列表"""articles = Article.objects.all().order_by('-published_date')# 示例 1: 在视图中使用 reverse 构造 URL (通常用于重定向)# 假设我们想在某个条件下重定向到创建文章页面# create_url = reverse('create_article')  # 通过名称获取 URL# print(f"Create Article URL: {create_url}")  # /articles/create/context = {'articles': articles,# 示例 2: 将反向解析的 URL 传递给模板# 这在需要 JavaScript 动态获取 URL 时很有用'create_article_url': reverse('create_article'),}return render(request, 'myapp/index.html', context)def article_detail(request, article_id):"""显示单篇文章详情"""article = get_object_or_404(Article, id=article_id)# 示例 3: 在视图中使用 reverse (例如,重定向到详情页后)# current_url = reverse('article_detail', kwargs={'article_id': article.id})# print(f"Current Article URL: {current_url}") # /articles/1/context = {'article': article}return render(request, 'myapp/detail.html', context)def create_article(request):"""创建新文章 (简化版,仅演示 reverse)"""if request.method == 'POST':# 这里省略表单处理和验证title = request.POST.get('title')content = request.POST.get('content')if title and content:article = Article.objects.create(title=title, content=content)# 示例 4: 使用 reverse 进行重定向 - 这是最常见的用法之一# 重定向到新创建文章的详情页detail_url = reverse('article_detail', kwargs={'article_id': article.id})return redirect(detail_url) # 等同于 redirect('article_detail', article_id=article.id)# redirect 函数内部也使用了 reversereturn HttpResponse("""<h1>Create New Article</h1><form method="post">{% csrf_token %}<label for="title">Title:</label><input type="text" name="title" required><br><label for="content">Content:</label><textarea name="content" required></textarea><br><button type="submit">Create</button></form><a href="{}">Back to List</a>""".format(reverse('index'))) # 在内联 HTML 中使用 reverse

# myapp/templates/myapp/index.html<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Article List</title>
</head>
<body><h1>Articles</h1><!-- 示例 5: 在模板中使用 url 模板标签 (Django 模板中的 reverse) --><a href="{% url 'myapp:create_article' %}">Create New Article</a><!-- 注意: 因为定义了 app_name='myapp',所以需要使用 'myapp:create_article' --><!-- 如果没有 app_name,则使用 'create_article' --><ul>{% for article in articles %}<li><!-- 示例 6: 使用 url 标签链接到详情页 --><a href="{% url 'myapp:article_detail' article_id=article.id %}">{{ article.title }}</a>(Published: {{ article.published_date|date:"M d, Y" }})</li>{% empty %}<li>No articles yet.</li>{% endfor %}</ul><!-- 示例 7: 使用视图中传递的反向解析 URL (来自 context) --><!-- 虽然这里用 url 标签更直接,但展示如何使用传递的 URL --><p><a href="{{ create_article_url }}">Create Article (via context)</a></p>
</body>
</html>

4.路由的命名空间

为什么需要命名空间?

想象一下,你有两个应用:blognews。它们都可能有名为 indexdetailcreate 的视图。如果没有命名空间:

# blog/urls.py
path('', views.index, name='index') # blog 的首页
path('<int:post_id>/', views.detail, name='detail') # blog 的详情页# news/urls.py
path('', views.index, name='index') # news 的首页
path('<int:article_id>/', views.detail, name='detail') # news 的详情页

当你在代码中使用 reverse('index') 或模板中使用 {% url 'index' %} 时,Django 无法确定你指的是 blogindex 还是 newsindex,这会导致冲突和不可预测的行为。

命名空间就是为了解决这个问题而生的!

命名空间的类型

Django 支持两种命名空间:

  1. 应用命名空间 (Application Namespace): 通过 app_name 变量在应用的 urls.py 中定义。它标识了 URL 模式属于哪个 Django 应用。
  2. 实例命名空间 (Instance Namespace): 在项目 urls.py 的 include() 函数中通过 namespace 参数定义。它标识了应用的一个具体实例。一个应用可以有多个实例。
myproject/
├── blog/                 # 博客应用
│   ├── views.py
│   ├── urls.py
│   └── models.py
├── news/                 # 新闻应用
│   ├── views.py
│   ├── urls.py
│   └── models.py
└── myproject/└── urls.py           # 项目主 URL 配置

1. 定义应用命名空间 (app_name)

在每个应用的 urls.py 文件中,设置 app_name

blog/urls.py:

from django.urls import path
from . import views# 👉 定义应用命名空间
app_name = 'blog'urlpatterns = [# 现在这些 URL 名称属于 'blog' 命名空间path('', views.index, name='index'),           # 完整名称: blog:indexpath('<int:post_id>/', views.detail, name='detail'), # 完整名称: blog:detailpath('create/', views.create, name='create'),  # 完整名称: blog:create
]

news/urls.py:

from django.urls import path
from . import views# 👉 定义应用命名空间
app_name = 'news'urlpatterns = [# 这些 URL 名称属于 'news' 命名空间path('', views.index, name='index'),           # 完整名称: news:indexpath('<int:article_id>/', views.detail, name='detail'), # 完整名称: news:detailpath('create/', views.create, name='create'),  # 完整名称: news:create
]

2. 在项目 URL 中包含应用 (可选:定义实例命名空间)

在项目主 urls.py 中,使用 include() 包含应用的 URL 配置。

myproject/urls.py:

from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),# 方法 1: 只包含,不指定实例命名空间# 此时,实例命名空间默认等于应用命名空间 ('blog' 和 'news')path('blog/', include('blog.urls')),    # 实例命名空间: 'blog'path('news/', include('news.urls')),    # 实例命名空间: 'news'# 方法 2: 显式指定不同的实例命名空间 (高级用法)# path('my-blog/', include('blog.urls', namespace='personal_blog')), # 实例命名空间: 'personal_blog'# path('company-news/', include('news.urls', namespace='corporate_news')), # 实例命名空间: 'corporate_news'
]

注意: 如果在 include() 中没有指定 namespace 参数,Django 会使用 app_name 的值作为实例命名空间

如何使用命名空间

一旦定义了命名空间,你就可以在代码和模板中精确地引用 URL。

在 Python 代码中使用 reverse()

from django.urls import reverse
from django.shortcuts import redirectdef some_view(request):# ✅ 正确:使用完整的命名空间名称blog_index_url = reverse('blog:index')           # 结果: '/blog/'news_detail_url = reverse('news:detail', kwargs={'article_id': 5}) # 结果: '/news/5/'blog_create_url = reverse('blog:create')         # 结果: '/blog/create/'# 🔁 重定向到博客首页return redirect('blog:index') # 等同于 redirect(reverse('blog:index'))# 🔁 重定向到新闻详情页# return redirect('news:detail', article_id=10)

在 Django 模板中使用 {% url %} 标签

<!-- templates/some_template.html --><!DOCTYPE html>
<html>
<head><title>My Site</title>
</head>
<body><h1>Welcome!</h1><!-- ✅ 正确:使用命名空间 --><a href="{% url 'blog:index' %}">Go to Blog</a>           <!-- 生成: /blog/ --><a href="{% url 'news:index' %}">Go to News</a>           <!-- 生成: /news/ --><!-- 带参数的 URL --><a href="{% url 'blog:detail' post_id=1 %}">Read Blog Post 1</a>   <!-- 生成: /blog/1/ --><a href="{% url 'news:detail' article_id=2 %}">Read News Article 2</a> <!-- 生成: /news/2/ --><!-- 创建新内容 --><a href="{% url 'blog:create' %}">Write a Blog Post</a>   <!-- 生成: /blog/create/ --><a href="{% url 'news:create' %}">Submit News</a>         <!-- 生成: /news/create/ --><!-- ❌ 错误:不使用命名空间 (如果存在冲突,行为不确定) --><!-- <a href="{% url 'index' %}">This might not work as expected!</a> -->
</body>
</html>

实例命名空间的高级用法

假设你想为同一个 blog 应用创建两个不同的实例(例如,个人博客和公司博客)。

myproject/urls.py (修改):

from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),# 👉 为同一个应用创建两个不同实例,使用不同的实例命名空间path('personal/', include('blog.urls', namespace='personal_blog')), # 实例命名空间: personal_blogpath('company/', include('blog.urls', namespace='company_blog')),  # 实例命名空间: company_blog
]

在代码中使用实例命名空间:

# Python 代码
personal_blog_index = reverse('personal_blog:index') # 结果: '/personal/'
company_blog_index = reverse('company_blog:index')   # 结果: '/company/'# 模板
<a href="{% url 'personal_blog:index' %}">My Personal Blog</a>  <!-- 生成: /personal/ -->
<a href="{% url 'company_blog:index' %}">Company Blog</a>       <!-- 生成: /company/ -->

重要: 当使用实例命名空间时,reverse() 会优先查找实例命名空间。如果找不到,它会回退到应用命名空间。


命名空间查找规则

当你调用 reverse(viewname, current_app=None){% url 'viewname' %} 时,Django 按以下顺序查找:

  1. current_app 参数: 如果提供了 current_app,Django 会首先在该应用实例的命名空间中查找。
  2. 实例命名空间: 如果没有 current_app,Django 会根据当前请求的 URL 匹配到的 include() 的 namespace 来查找。
  3. 应用命名空间: 如果实例命名空间未找到或未定义,Django 会回退到 app_name 定义的应用命名空间。
  4. 无命名空间: 最后,如果以上都失败,才会查找无命名空间的 URL 名称。

最佳实践与总结

  1. 始终使用 app_name: 为每个应用的 urls.py 文件定义 app_name。这是避免命名冲突的最基本和最重要的步骤。
  2. 在模板和代码中使用完整名称: 始终使用 'app_name:url_name' 的格式(如 'blog:index')来引用 URL。
  3. 实例命名空间用于高级场景: 通常情况下,include('app.urls') 就足够了,实例命名空间默认等于 app_name。只有在需要部署同一个应用的多个独立实例时才显式使用 namespace 参数。
  4. 提高可维护性: 命名空间使你的代码更清晰。看到 'blog:create' 就知道这是博客应用的创建页面,而不会与 'news:create' 混淆。
  5. 解耦应用: 应用可以独立开发,只要定义好自己的 app_name 和 URL 名称,集成到项目中时就不会轻易产生冲突。

通过使用命名空间,你可以构建出结构清晰、易于维护且可扩展的 Django 项目。

如果 url 有多层 include 嵌套,要怎么写?

只要记住一句话:
用“冒号”一级一级拼出完整的“实例命名空间链”,最后才是应用命名空间 + 路由名。
顺序永远是:

最外层实例 : 次外层实例 : … : 应用命名空间 : 路由名

✅ 举个 3 层嵌套的例子

目录结构示意

mysite/urls.py                 # 根
user/urls.py                 # 第 1 层 include
blog/urls.py                 # 第 2 层 include
article/urls.py                 # 第 3 层,真正放路由
1) 根 urls.py(第 0 层)
# mysite/urls.py
from django.urls import path, includeurlpatterns = [path('user/', include('user.urls', namespace='u')),   # 实例 u
]
2) user/urls.py(第 1 层)
# user/urls.py
from django.urls import path, includeurlpatterns = [path('blog/', include('blog.urls', namespace='b')),   # 实例 b
]
3) blog/urls.py(第 2 层)
# blog/urls.py
from django.urls import path, includeurlpatterns = [path('article/', include('article.urls')),            # 没有新的 namespace
]
4) article/urls.py(第 3 层,真正路由)
# article/urls.py
from django.urls import path
from . import viewsapp_name = 'article'                                      # 应用命名空间
urlpatterns = [path('<int:pk>/', views.detail, name='detail'),
]

✅ reverse 写法(在 Python 代码里)

from django.urls import reverseurl = reverse('u:b:article:detail', args=[2024])
# 结果:/user/blog/article/2024/
  • u —— 最外层实例(根 include)

  • b —— 次外层实例(user include)

  • article —— 应用命名空间(article/urls.py 里的 app_name

  • detail —— 路由名


✅ 模板里

{% url 'u:b:article:detail' 2024 %}

如果某一级没有 namespace

  • 没有 namespace 的那一级 不会出现在链里

  • 例子中 blog/urls.py 再 include article 时没给 namespace,所以链里直接跳到 article


速记口诀

“实例一路冒号拼,最后是 app_name:路由名”

实例命名空间 有什么用? 什么时候必须设置?

一句话:
实例命名空间 = 给同一份 URLconf 起“不同的名字”,让 Django 在反向解析时能分清“到底用的是哪一份”。
它只在 同一份 URLconf 被 include 多次 时才“必须设置”,否则可以不设。


1. 什么时候“必须设置”?

场景是否必须设置实例命名空间
同一个 app 的 urls.py 只被 include 一次❌ 不必设置
同一个 app 的 urls.py 被 include 多次(例如多语言、多站点、多租户)✅ 必须设置,否则 reverse() / {% url %} 无法区分

2. 没有实例命名空间会怎样?

假设你有:

# blog/urls.py
app_name = 'blog'
urlpatterns = [path('article/<int:pk>/', views.detail, name='article-detail'),
]# 主 urls.py
urlpatterns = [path('en/', include('blog.urls')),   # 想给英文站点path('zh/', include('blog.urls')),   # 想给中文站点
]
  • 两个 include 都没给 namespace都叫同一个应用命名空间 blog

  • 反向解析 reverse('blog:article-detail', args=[1]) 时,Django 不知道应该返回 /en/article/1/ 还是 /zh/article/1/,于是抛 NoReverseMatch


3. 加了实例命名空间就安全

urlpatterns = [path('en/', include('blog.urls', namespace='en_blog')),path('zh/', include('blog.urls', namespace='zh_blog')),
]
  • 现在有两条实例命名空间en_blogzh_blog

  • 反向解析可以明确写:

reverse('en_blog:article-detail', args=[1])   # /en/article/1/
reverse('zh_blog:article-detail', args=[1])   # /zh/article/1/

4. 小结

概念作用什么时候必须出现
应用命名空间 (app_name)让同一 app 的所有路由共享一个“逻辑组名”只要想在 reverse() 里用 app:route 形式,就必须写
实例命名空间 (namespace=xxx)同一份应用被部署多次时,给每一次 include 起独一无二的名字同一份 URLconf 被 include 多次时必须设置,否则反向解析冲突

一句话:

“只有同一份 URLconf 被 include 多次,才需要实例命名空间来区分;否则只保留应用命名空间即可。”

实例命名空间 、 应用命名空间, 哪个是必须的?

在 Django 的 URL 反向解析体系里,必须有“应用命名空间”(app_name) 这一级,否则 reverse()/{% url %} 无法工作。
“实例命名空间”(namespace) 只有在“同一份 URLconf 被 include 多次”时才额外出现,它并不能取代 app_name


实验验证

  1. blog/urls.py 写成:

# blog/urls.py   —— 故意不写 app_name
from django.urls import path
from . import viewsurlpatterns = [path('article/<int:pk>/', views.detail, name='article-detail'),
]
  1. 在主路由中:

# 只给 namespace,不给 app_name
urlpatterns = [path('en/', include('blog.urls', namespace='en')),
]
  1. 视图或模板里尝试:

reverse('en:article-detail', args=[1])
# 或
{% url 'en:article-detail' 1 %}

结果
Django 抛出 ImproperlyConfigured: App with label 'en' could not be found. …(或 NoReverseMatch),
因为它找不到名为 article-detail应用命名空间


正确姿势

# blog/urls.py
app_name = 'blog'            # 必须给
urlpatterns = [path('article/<int:pk>/', views.detail, name='article-detail'),
]# 主 urls.py
urlpatterns = [path('en/', include('blog.urls', namespace='en')),  # namespace 可选
]

反向解析:

reverse('en:blog:article-detail', args=[1])   # 有实例
# 或
reverse('blog:article-detail', args=[1])      # 无实例

结论

  • 应用命名空间 (app_name) 是必填项

  • 实例命名空间 (namespace) 只是可选的“区分符”

  • 没有 app_name,任何 reverse()/{% url %} 都会失败。

  • 因为优先查找,实例命名空间,reverse()参数可以用 实例命名空间,不写app_name

http://www.dtcms.com/a/325201.html

相关文章:

  • word格式设置-论文写作,样式,字号等
  • 在Debian上安装MySQL
  • java设计模式之开闭原则使用举例
  • 5种无需USB线将照片从手机传输到笔记本电脑的方法
  • Linux 流编辑器 sed 详解
  • 实体瘤疗效评估标准
  • 图像打标工具/方法的分类和特点说明
  • Launcher3启动
  • Ansys Mechanical中的声学分析
  • 人工智能与农业:农业的革新
  • Nginx学习笔记(二)——环境准备(VMware CentOS版)
  • Mybatis @Param参数传递说明
  • Postgresql源码(148)hash表的调试方法与技巧
  • Apache IoTDB 全场景部署:基于 Apache IoTDB 的跨「端-边-云」的时序数据库 DB+AI
  • ZeroNews:如何构建安全(无需 V*N!)的工业物联网连接
  • 企业高性能 Web 服务部署实践(基于 RHEL 9)
  • DNS(域名系统)
  • IP分片(IP Fragmentation)
  • NS3中的路由模型-5 OLSR路由协议
  • 疏老师-python训练营-Day42Grad-CAM与Hook函数
  • MySQL 基础操作教程
  • 学习嵌入式第二十五天
  • 机器学习——K-means聚类
  • 个人效能是一个系统
  • 【YOLO11改进 - C3k2融合】C3k2融合EBlock(Encoder Block):低光增强编码器块,利用傅里叶信息增强图像的低光条件
  • 学习嵌入式的第十六天——C语言——位运算
  • tlias智能学习辅助系统--原理篇-SpringBoot原理-自动配置-自定义starter
  • 【走进Docker的世界】深入理解Docker网络:从模式选择到实战配置
  • #Datawhale AI夏令营#第三期全球AI攻防挑战赛(AIGC技术-图像方向)
  • [Shell编程] Shell的正则表达式