Django框架 - 应用命名空间app_name和实例命名空间namespace的区别
Django框架 - 区分应用命名空间 app_name 和 实例命名空间 namespace
Django框架学习笔记 - include()区分app_name和namespace
前言
查看官方文档:
这部分描述有点晦涩难懂,我们用不同的例子来比较以下二者的区别:
我的Django版本:4.2.2
项目名称:djangoProject
有子应用:note
app_name的两种写法
app_name有两种写法,一种是写在根路由,一种是写在子路由:
-
在根路由中定义
# urls.py urlpatterns = [ path('notes/', include(('note.urls', 'note'))), ] # note/urls.py urlpatterns = [ path('namespace_test/', views.namespace_test, name='namespace_test'), ]
-
在子路由中定义
# urls.py urlpatterns = [ path('notes/', include(('note.urls', 'note'))), ] # note/urls.py app_name = "note" urlpatterns = [ path('namespace_test/', views.namespace_test, name='namespace_test'), ]
app_name顾名思义应用命名空间,通常与子应用同名,因此常写在子应用 app.urls 中指定;
当同时在主路由urls和子路由app.urls中指定指定时,主路由的命名无效。
# urls.py
urlpatterns = [
path('notes/', include(('note.urls', 'notes'))),
]
# note/urls.py
app_name = "note"
urlpatterns = [
path('namespace_test/', views.namespace_test, name='namespace_test'),
]
namespace的写法
namespace在根路由中定义
# urls.py
urlpatterns = [
path('notes/', include('note.urls', namespace='note')),
]
# note/urls.py
app_name = "note"
urlpatterns = [
path('namespace_test/', views.namespace_test, name='namespace_test'),
]
或
# urls.py
urlpatterns = [
path('notes/', include(('note.urls', 'note'), namespace='note')),
]
namespace为实例命名空间,通常在创建实例,即 path(route, include()) 函数中指定;
namespace默认值
当指定app_name,不指定namespace时:
# urls.py
urlpatterns = [
path('notes/', include('note.urls')),
]
# note/urls.py
app_name = "note"
urlpatterns = [
path('namespace_test/', views.namespace_test, name='namespace_test'),
]
# note/views.py
from django.http import HttpResponse
import logging
# logging日志配置可以参考我的另一篇文章:https://blog.csdn.net/qq_42694871/article/details/131528016
logger = logging.getLogger('django')
def namespace_test(request):
""" 测试命名空间的区别 """
logger.info("app_name: %s", request.resolver_match.app_name)
logger.info("namespace: %s", request.resolver_match.namespace)
logger.info("view_name: %s", request.resolver_match.view_name)
return HttpResponse('success')
可以看到,namespace默认等于app_name的值。
namespace的唯一性
基于同一个子应用note (即同一个app_name) 创建多个path()实例:
# urls.py
urlpatterns = [
# 唯一的namespace="admin_note"
path('admin_note/', include('note.urls', namespace='admin_note')),
# 唯一的namespace="tourist_note"
path('tourist_note/', include('note.urls', namespace='tourist_note')),
# 不唯一的namespace="user_note"
path('user_test_note/', include('note.urls', namespace='user_note')),
path('user_dev_note/', include('note.urls', namespace='user_note')),
path('user_pro_note/', include('note.urls', namespace='user_note')),
]
编译时会生成警告:URL命名空间 user_note 不唯一
:
请求每个url均可正常访问。
说明Django不推荐使用重复的namespace,而不是禁止。
根据警告信息我们可以知道,不唯一的namespace可能导致无法reverse()其下所有的url:
# 查询namespace='user_note'的实例,返回第一个匹配的url
>>> reverse('user_note:namespace_test')
'/user_test_note/namespace_test/'
# 查询current_app='user_note'下的app_name='note'的实例,返回第一个匹配的url
>>> reverse('note:namespace_test', current_app='user_note')
'/user_test_note/namespace_test/'
# 交换urls中user_test_note/和user_pro_note/的顺序,同样返回第一个
>>> reverse('user_note:namespace_test')
'/user_pro_note/namespace_test/'
>>> reverse('note:namespace_test', current_app='user_note')
'/user_pro_note/namespace_test/'
可以看到,虽然没有报错,但是只能对第一个创建的实例下的路由进行反转。
也可能会报错:NoReverseMatch: ‘xxx’ is not a registered namespace
对其他唯一的namespace:
# 查询namespace='admin_note'的实例
>>> reverse('admin_note:namespace_test')
'/admin_note/namespace_test/'
# 查询namespace='tourist_note'的实例
>>> reverse('tourist_note:namespace_test')
'/tourist_note/namespace_test/'
# 查询current_app='admin_note'下app_name='note'的实例
>>> reverse('note:namespace_test', current_app='admin_note')
'/admin_note/namespace_test/'
# 查询current_app='tourist_note'下app_name='note'的实例
>>> reverse('note:namespace_test', current_app='tourist_note')
'/tourist_note/namespace_test/'
# 查询不存在的current_app下app_name='note'的实例,返回最后一个url,但因为最后三个namespace重复,所以返回倒数第三个url
>>> reverse('note:namespace_test', current_app='noteapp')
'/user_test_note/namespace_test/'
可以看到,当namespace唯一时,reverse()函数可以成功解析。
app_name的唯一性
从上述示例可以看出,同一个子应用的app_name可以不唯一,即无论有多少实例,应用app_name始终为同一个。
-
同一个应用使用不同的app_name:
# urls.py urlpatterns = [ path('admin_note/', include(('note.urls', 'adminNote'), namespace='admin_note')), path('tourist_note/', include(('note.urls', 'touristNote'), namespace='tourist_note')), ] # note/urls.py urlpatterns = [ path('namespace_test/', views.namespace_test, name='namespace_test'), ]
编译与运行无异常,
reverse()
成功:>>> reverse('admin_note:namespace_test') '/admin_note/namespace_test/' >>> reverse('tourist_note:namespace_test') '/tourist_note/namespace_test/' >>> reverse('tourist_note:namespace_test') '/tourist_note/namespace_test/' >>> reverse('adminNote:namespace_test') '/admin_note/namespace_test/' >>> reverse('touristNote:namespace_test') '/tourist_note/namespace_test/'
-
不同的应用使用同一个app_name:
# urls.py urlpatterns = [ path('notes/', include('note.urls', namespace='note')), path('plans/', include('plan.urls', namespace='plan')), ] # note/urls.py app_name = "app" urlpatterns = [ path('namespace_test/', views.namespace_test, name='namespace_test'), ] # plan/urls.py app_name = "app" urlpatterns = [ path('namespace_test/', views.namespace_test, name='namespace_test'), ]
编译与运行无异常,
reverse()
成功:>>> reverse('note:namespace_test') '/notes/namespace_test/' >>> reverse('plan:namespace_test') '/plans/namespace_test/' >>> reverse('app:namespace_test') '/plans/namespace_test/' >>> reverse('app:namespace_test', current_app='note') '/notes/namespace_test/' >>> reverse('app:namespace_test', current_app='plan') '/plans/namespace_test/'
结论
- app_name为应用命名空间,通常写在子应用的urls.py中:
app_name = "app_name"
,与子应用同名。 - app_name的唯一性没有要求,通常为每个子应用设定各自的app_name。
- 同一个子应用即可以使用同一个app_name,也可以使用不同的app_name;
- 不同的子应用,同样既可以使用同一个app_name,也可以使用不同的app_name;
- namespace为实例命名空间,通常写在主路由的urls.py中:
path(route, include(viewname, "namespace"))
. - namespace的值应该是唯一的,否则可能无法反转这个命名空间下的所有url。
- 当没有指定namespace的值时,它默认等于app_name的值。因此当同一个app_name有不同实例时,需要注意设定namespace唯一。
按照代码规范写法,app_name相当于子应用的实际名字,而namespace相当于子应用在某个实例上的昵称。
更多推荐
所有评论(0)