django -- urls.py

这个模块是python单吗,而且是一个将URL路径和python方法进行映射的代码。

这个mapping关系可以根据需求,可长可短。可以涉及到其他的mappings。因为是python代码,所以也可以进行动态的修改。

django提供了一种将urls翻译为其他语言的方式。

如何操作一个request请求

当用户发起一个请求的时候,下面就是django如何通过算法进行选择执行哪个python方法。

1: django决定简要使用个URLconfig模块。一般,这是一个ROOT_URLCONFI配置文件的一个值。但是如果发送过来的request请求有一个urlconfig属性。(通过中间软件设置),那么这个值在这里将会用到。

2:django加载python模块,并且寻找url规则进行匹配。这个url规则将会是一个path或者re_path的集合。

3:django通过各种的url规则,将会在第一个匹配到的规则那里停止下来。

4:一单匹配了其中一个url规则,django将会倒入并且调用对应的view。python的方法。view可以获取下面的数据。
    1:一个httprequest对象
    2:如果url规则返回的是一个没有命名的组,那么匹配到的将会是一个位置参数。
    3:关键字参数就是re表达式中的命名的组,
    4:

5:如果没有url规则匹配。或者说在这个过程中抛出了异常。django将会抛出异常。

from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

需要注意的是:
1:通过尖括号进行捕获值。
2:捕获的值可以可选的进行转换类型。比如上面的将year转化成为int。如果没有,除了斜杠之外的所有字符串都可以匹配。
3:没有必要去添加前置斜杠,因为每一个url都有。比如说 articales就不需要 /articals.

扫描二维码关注公众号,回复: 4882583 查看本文章

根据上面的例子,下面的调用。

/articles/2005/03/    匹配第3个      views.month_archive(request, year=2005, month=3).
/articles/2003/              匹配第一个    views.special_case_2003(request)
/articles/2003               不匹配
/articles/2003/03/building-a-django-site/   最后一个    views.article_detail(request, year=2003, month=3, slug="building-a-django-site").

 强转    int

str    除了斜杠以外的所有
int    0或者其他正整数,不包括负数。
slug   负数以及-_字母

path   匹配所有的非空字符包括/

添加强转规则。

为了更复杂匹配的需求。你自定义conventer类。标准如下:
1: 一个regex属性,而且是string。
2:一个to_python(self,value)方法,这个返回将匹配到的string转化为对应类型的值。这个值将会传入view方法中。如果不能转换成为给定的值,那么将会抛出异常。
3:一个to_url(sel,value)方法,将会将转化后的数据转化成为一个字符串,这个将在URL中使用。

class FourDigitYearConverter:
    regex = '[0-9]{4}'

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return '%04d' % value

通过方法register_converter进行注册。

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, 'yyyy')

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<yyyy:year>/', views.year_archive),
    ...
]

通过正则表达式。
如果path和converter语法都不能满足你定义URL规则,那么你可以通过正则进行获取。如果要这样就需要使用re_path,而不是path.
在python正则表达式中。为了获取一个命名的组,语法如下(?P<name>pattern)。name就是组的名字,pattern就是规则。

from django.urls import path, re_path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', 
views.article_detail),
]

这个例子和上面的例子中工作的效果完全一模一样。除了。
1:具体的URL将要匹配得更严格。比如,10000年将不会匹配,因为year整型值被认定为四位数。
2:每一个数据都会被当做整型进行匹配,和匹配的顺序没有关系。

当从使用path到使用gre_path,我们需要关切view参数的数据类型可能会发生变化,所以你有必要去修改你的view。反之亦然。

我们同样可以使用未命名的参数,虽然这样跟简单。但是不建议这么做。除非明确只有一个数据的时候。而且这种方法更容易导致错误。还有命名和未命名的组不能混合使用,因为,两者混合,未命名的将会被忽略掉。

而且同样不建议使用嵌套组,但是可以通过(?:pattern)进行避免。 

URLconf搜索用来干啥的呢?

这个仅仅用来搜索url,把url当成string类型来使用。这个不包括get,post参数。或者说是域名。

比如说对于 https://www.example.com/myapp/,URLconf仅仅查找 myapp/.
同样
https://www.example.com/myapp/?page=3 ,也仅仅查找myapp,而忽略参数。

urlconf不会查看requets的方法,也就是说,不管你怎么样,都要经过我这儿。

为view设置默认值。

一个很方便的使用方式就是为view的参数设置哦认知。比如说。

# URLconf
from django.urls import path

from . import views

urlpatterns = [
    path('blog/', views.page),
    path('blog/page<int:num>/', views.page),
]

# View (in blog/views.py)
def page(request, num=1):
    # Output the appropriate page of blog entries, according to num.
    ...

所有的在urlpatterns中的规则都只会在第一次使用链接的时候编译。也就是匹配,逐一匹配url。

urlpattern对象必须是一个由path或者re_path组成的集合。

使用其他的urlpattern

z在任何时候,你的urlpatterns都可以包含其他urlconfig模块的内容。这个root连接必须是前后关系,不能是子父,只能是父子关系的那种。这是为了满足真正的需要,但是实际上可以 的。
比如下面的这个例子是Django本身对其他的引用。包含了其他的URLconf模块。

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path('community/', include('aggregator.urls')),
    path('contact/', include('contact.urls')),
    # ... snip ...
]

无论什么时候Django遇到了include。它都会截取掉匹配的字符串,然后将剩下的交给include里面的URLconf。去做更深远的处理。

另一种可能是通过path包含一个额外的URLpattern。比如说下面的例子。

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path('reports/', credit_views.report),
    path('reports/<int:id>/', credit_views.report),
    path('charge/', credit_views.charge),
]

urlpatterns = [
    path('', main_views.homepage),
    path('help/', include('apps.help.urls')),
    path('credit/', include(extra_patterns)),
]

这个例子就是在path的第二个参数include中包含了前面的include。然后再urlpatterns的第一个就是调用了其他view里面的方法。上面的credit/reports将会被传递给 credit_views.report方法。

当一个prefix被多次重复的使用的时候,我们就可以通过删除荣誉的方式进行使用。比如下面的这些。

from django.urls import path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/history/', views.history),
    path('<page_slug>-<page_id>/edit/', views.edit),
    path('<page_slug>-<page_id>/discuss/', views.discuss),
    path('<page_slug>-<page_id>/permissions/', views.permissions),
]

也就是有一些网站在中间插入了文件的年月日等信息作为数据项。后面的也都统一。

我们可以通过包含的方式进行简化。

from django.urls import include, path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/', include([
        path('history/', views.history),
        path('edit/', views.edit),
        path('discuss/', views.discuss),
        path('permissions/', views.permissions),
    ])),
]

确实有点东西呀。

获取参数。

一种通过include urlconf的方式进行包含的是可以获取所有捕获到的数据的,所以下面的这些列子是合法的。

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path('<username>/blog/', include('foo.urls.blog')),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog.index),
    path('archive/', views.blog.archive),
]

也就是说,main.py中捕获的username将会传递给foo.urls.blog中。

可以通过dict的方式传递其他额外的数据。

from django.urls import path
from . import views

urlpatterns = [
    path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]

/blog/2005/        views.year_archive(request, year=2005, foo='bar')

如果获取到和我们传入的冲突了,那么将会使用字典里面的而不是url中捕获的。

给include传递额外的数据。

# main.py
from django.urls import include, path

urlpatterns = [
    path('blog/', include('inner'), {'blog_id': 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path('archive/', views.archive),
    path('about/', views.about),
]

 需要注意的是通过include包含其他conf,所有的path都将会收到传递过去的数据。也不管这些view是否真的接受这些参数。也正是这个原因,你最好确认一下是不是所有的urlconf都接受这个额外的数据。

# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path('blog/', include('inner')),
]

# inner.py
from django.urls import path

urlpatterns = [
    path('archive/', views.archive, {'blog_id': 3}),
    path('about/', views.about, {'blog_id': 3}),
]

和上面的类似。

path的命名

给自己当前的URL命名,可以让你在其他地方很明显的调用。尤其是在模版里面。这个强大的特性可以让你在一个文件里面给所有的全局URL赋值。

path专讲

path是一个方法,返回一个元素。元素类型为 <class 'django.urls.resolvers.URLResolver'>

path的原型path(routeviewkwargs=Nonename=None)
 

from django.urls import include, path

urlpatterns = [
    path('index/', views.index, name='main-view'),
    path('bio/<username>/', views.bio, name='bio'),
    path('articles/<slug:title>/', views.article, name='article-detail'),
    path('articles/<slug:title>/<int:section>/', views.section, name='article-section'),
    path('weblog/', include('blog.urls')),
    ...
]


首先route参数应该是一个string类型或者是一个gettext_lazy()方法,这里面包含了URL匹配规则。
这个string里面可能会有尖括号,会将捕获到的数据传递到view中。而且尖括号中可以有类型转换。这样也就改变了发送过去的类型。

view参数一个view的方法或者是as_view,也可以是一个 django.urls.include()方法。

kwargs 参数可以传递任意的参数过去。必须是dict类型。

name  普通是顺序匹配,这样可以自由匹配。而且重载的时候更加有效。link

url()是re_path的一个别名。

猜你喜欢

转载自blog.csdn.net/rubikchen/article/details/85942896