原文链接:https://www.cnblogs.com/maple-shaw/p/9282718.html

Django 1.11版本 URLConf官方文档

URL配置(URLconf)就像Django所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

我们就是以这种方式告诉Django,遇到哪个URL的时候,要对应执行哪个函数。

URLconf配置

基本格式:

from django.conf.urls import url
urlpatterns = [
     url(正则表达式, views视图,参数,别名),
]
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003), #前面写个响应地址,跟后面的函数有个对应关系。使用正则表达式跟浏览器地址栏url匹配,匹配上之后才获得后面这个函数
    url(r'^articles/([0-9]{4})/$', views.year_archive), #前面那条路由只能匹配一个,叫静态路由;本条能匹配多个url,叫做动态路由
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), #这里的是Django1.1版本的写法
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), #url就是一个类,如下图

参数说明:

  • 正则表达式:一个正则表达式字符串
  • views视图:一个可调用对象,通常为一个视图函数
  • 参数:可选的要传递给视图函数的默认参数(字典形式)
  • 别名:一个可选的name参数
  • Django 2.0版本中的路由系统是下面的写法(官方文档):

    from django.urls import path,re_path  #1.0版本的导入类变了
    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),
    

    2.0版本中re_path和1.11版本的url是一样的用法。

    为什么一启动访问的是这个界面,它其实已经做出了匹配了,它匹配访问的地址是/这个路径(http://127.0.0.1:8000/),因为url中没有这个路径,所以是访问不到的。你能访问到的路径它已经在1处显示出来了,照着它写就行了。

    这就是一个静态路由,

    参考:https://blog.csdn.net/qq_42491125/article/details/118491813

    r用来表示转义的,^以什么开头,如果去掉^号,那么前面加上别的内容也能匹配上,后面的能匹配上那它就能匹配成功,这不是我们想要的。加上它就是以blog开头,

  • 每个正则表达式前面的'r' 是可选的但是建议加上。
  • 那么加上表示以四个数字结尾,那么四个数字后面由下面的能匹配

    变成不能成功匹配:

    看下面,我想让它走函数2的,但是访问结果显示的是函数1的:

    匹配有个顺序是从上到下的匹配,先拿1处的和url匹配,匹配上了,就执行了1的函数,它就不会再往下取匹配了。那我们写严谨一点,加上$结尾符号,这样就正确匹配了。因此以后写的时候加个$,防止匹配函数的时候被前面的地址匹配成功而截获了。

  • urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
  • 如果前面第一个的前面加个斜线,那么访问需要添加一个斜线才能访问到页面,因为内部已经给我们加好了。

  • 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  • 当我们不写最后的/的时候,Django给我们做了301重定向了,重新get一次有/的location地址

    而上面那个最后不加斜线然后能做跳转的功能是可以修改的一个配置。默认是True:改为False那么最后不加斜线就404找不到页面了

    # 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项   在setting中添加这个配置
    APPEND_SLASH=True
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^articles/2003/$', views.special_case_2003),
        url(r'^articles/([0-9]{4})/$', views.year_archive),
        url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
        url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
    
  • urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
  • 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
  • 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  • 每个正则表达式前面的'r' 是可选的但是建议加上。
  • # 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
    APPEND_SLASH=True

    Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。

    其效果就是:

    我们定义了urls.py:

    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
        url(r'^blog/$', views.blog),
    

    访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/ 。

    如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时就会提示找不到页面。

    分组命名匹配

     给正则加个()就是分组,分组之后访问是什么结果呢?报错我们多给了函数一个参数。这是因为分组之后会把分组的内容提出来,并传递给匹配到的函数

    浏览器访问请求匹配到了这条路由,分组将分组中匹配到的内容传递到后面的函数,后面的函数用位置参数接收这个内容,这个内容是url中对应传来的字符串类型数据(捕获的参数永远是字符串)。分组作用就是从url中额外获取一些东西,而且自动将它传递给函数的参数。

    分组作用:将分组的参数按照位置传参传递给视图函数

    我们还可以在url路由中写多个分组,那么函数中就多个参数:

     之前我们直接在url路径上获取参数   id=2这种参数

    那么既然有了分组了能不能把id的包含在路径里面:http://127.0.0.1:8000/blog/1111/22/2/

    那么我们把之前项目出版社的改一下,改成分组的方法:

    修改了之后那后面的就是显示路径了,而不是?拼接的内容了,那么出版社展示页的编辑按钮改成如下:

    而url路由后面就添加\d+,因为你的id是最少一位数的,这样的话我们就能匹配到这里了,但是对应的编辑函数后面需要捕获到请求传过来的这个数,那么需要加括号使用分组,并且我的函数需要位置参数来接收这个分组传过来的内容,因为下面用到的它作为pk,我们直接改形参成pk。并且之前get获取pk的语句可以注释掉了

    修改了之后获取编辑对象没有问题的:

     现在给分组命名,并将之前函数的两个形参删掉,然后报错:  blogs() got an unexpected keyword argument 'year'

    由报错内容可知,分组命名之后应该是将分组内容以关键字形式传递给函数

     添加了两个关键字参数并且关键字和分组命名的名称是一样的,这样就能在视图函数中获取到url传递过来的路径信息了。

    命名分组作用:将命名分组的参数按照关键字传参传递给视图函数

    那么刚才的那个编辑出版社的可以改成命名分组,如下:

    用不用命名分组都可以,建议使用命名分组,这样看到分组命名就知道传的这个参数是什么作用。只是用了分组的话不能看出这个参数是什么

    上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。

    在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。

    在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式。

    下面是以上URLconf 使用命名组的重写:

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^articles/2003/$', views.special_case_2003),
        url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
        url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
        url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
    

    这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。

    例如,针对URL /articles/2017/12/相当于按以下方式调用视图函数:

    views.month_archive(request, year="2017", month="12")

    在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。

    至于究竟应该使用哪一种,你可以根据自己的喜好来决定。

    URLconf匹配的位置

    URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。

    例如,http://www.example.com/myapp/ 请求中,URLconf 将查找 /myapp/ 。

    在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找 /myapp/ 。

    URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POSTGETHEAD等等 —— 都将路由到相同的函数。

    捕获的参数永远都是字符串

    每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

    传递到视图函数views.year_archive() 中的year参数永远是一个字符串类型。

    视图函数中指定默认值

    # urls.py中
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^blog/$', views.page),
        url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
    # views.py中,可以为num指定默认值
    def page(request, num="1"):
    View Code
    

      这里2处用了命名分组,分组的捕获到的内容传递给视图函数。1和2这两个要是一致会出现问题,1是不传参数的,2是多传了一个参数。实际上在3处函数中写的时候是指定了一个默认参数,1匹配到的时候就是不传num值,所以函数就使用num=1的这个值;如果2处page后面捕获了一个2,那么分组命名num会将num=2传递给3处的函数,使得函数使用传递过来的num是2。这样的话那么这两种url匹配上了都不会报错了。不传就用默认的值,传了就用传递的值。一般是用在分页,不传的话显示第一页的内容,博客里面显示你第一页的数据;如果传的话,博客就显示的你传的页码的数据。因此,多个url可以去指定同一个函数,但是你想让它不出问题的话要让他们参数是统一的,可以使用上默认参数。

    在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。

    如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。

    include其他的URLconfs

    根据功能和业务的增多url会越来越多:

    我们需要再开发app,app就能将功能划分开来,app里面写上了不同的业务。如果是多个app的话,一个项目可能不是你一个人在开发,是多个人协同开发。多个人协同开发用什么,可以用git做协同开发。 现在的情况是所有的地址都写在url.py里面。假如是两个人写项目,一个人负责一个app,他们写的路径都写在url.py文件里面,同时编辑一个文件,有人写了这部分,另一个人写了另外一部分。如果某个人不小心把另外一人写的东西删掉了或者两个人写的东西有冲突,那么将来你合并起来的时候是有问题的。那么需要解决冲突的问题。

    用的时候是这样,在功能分类的时候将功能写在app里面了,你的对应关系还写的同一个地方的时候,这个问题也会逐渐的增多,让每人去查找的时候也会很不方便。因此url地址和函数的对应关系应该跟你的app在一块,使用和查找都归这个app,这就需要用到include其它的urlconfs了

    新建一个urls.py在app01中,并将之前项目app01的url剪切到app01下的urls.py文件中,因为导入视图函数模块是当前目录,直接从 . 导入

    那么前端访问过来Django如何知道用哪个urls.py呢,这是根据settings中的配置来的,指定根url配置。由于这个urls可以修改,所以也不一定就是项目settings文件同级目录下的urls文件

    那么指定的根url配置应该如何写呢:

    从模块.conf下的urls导入include
    将第一层的目录匹配成app的名字,匹配到的包含对应app下的urls,这叫包含,也叫路由规划

    这样的话访问的时候它首先让找对应的app,

    不写/还是报错:

    加上/它会提示你后面怎么写:

    后面再写上blog就能访问到了:它是先拿根url配置下的进行匹配,匹配完了再拿后面include的urls再进行匹配,匹配上之后执行include的urls后面对应的函数
    如下:app01就像是一级目录,也就是先找到一级标题app01,再找二级标题blog,二级标题下也可以再写include三级标题,有没有必要写这么复杂的就看你的情况了。

    那么一级标签最后面/不加了,我就访问不到这个路径了

    那么只要把这个/去掉了才能访问:

    之前看的是根url配置中的/不需要我们加,Django帮我们加了。而根url配置中的url和app中的url中间需要一个/需要我们自己添加,要么添加在根url配置的后面,要么添加在app路径的前面,选择一个添加就能正常访问。如果都不加那么它们两个之间没有//才能访问到;如果都加,那么它们两个之间有两个//,那么我们访问也必须写两个//才能访问到。

    组件那里也有include这个同名的方法,tag那里有个inclusion_tag

    #At any point, your urlpatterns can “include” other URLconf modules. This
    #essentially “roots” a set of URLs below other ones.
    #For example, here’s an excerpt of the URLconf for the Django website itself.
    #It includes a number of other URLconfs:
    from django.conf.urls import include, url
    urlpatterns = [
       url(r'^admin/', admin.site.urls),
       url(r'^blog/', include('blog.urls')),  # 可以包含其他的URLconfs文件
    

    传递额外的参数给视图函数(了解)

    url函数中有kwargs,

    那么我们可以在app下urls中添加字典

    如下,这里报错:blog() got an unexpected keyword argument 'year'

    也就是说这里的字典它以关键字参数传递给视图函数

    那么要在视图函数中用app下url函数中传递的字典键值对,我们需要在函数中定义关键字参数的形参。不定义的话会报错,定义的形参不与字典中的键同名会报错

    我们字典中传递的是int,视图函数中接收的就是int类型。而分组命名中的内容,本身路径就是字符串类型,函数中获得的也是字符串类型。

    作用:也就是说我们在url函数中可以使用字典额外的传递一些参数给视图函数。我们也可以不用这样传参数,也可以直接在视图函数中定义默认参数year=2019

    字典传递多个键值对:

     那么我们字典中传递和分组命名一样的关键字参数,那么字典传递的参数优先级要高于分组命名传递的关键字参数。相当于使用字典中update方法,用后面的字典更新掉分组命名中的字典

    URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。

    django.conf.urls.url() 可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
    

    在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。
    当传递额外参数的字典中的参数和URL中捕获值的命名关键字参数同名时,函数调用时将使用的是字典中的参数,而不是URL中捕获的参数。

    命名URL和URL反向解析

    比如视图函数中很多重定向到某个路径(/publiser_list/),那么我们在url函数中将这个路径(^publisher_list/)修改掉(^publisher/),那么视图函数或模板链接中在使用它的地方还需要很麻烦地一一去修改。这样的话视图函数和模板中的这些路径就定死了,不够灵活。这样就用到了URL命名和反向解析

    URL命名,url函数中有个name参数

    给我们的url函数中传递name参数

     我先将根url配置中的app01前缀去掉,让所有的找到app01里面的url,然后在根下直接拼接app01中访问的^index/路径。在index页面中的a标签使用链接是/blog/的路径,

    点击博客能正常跳转到博客页面,但是/blog/这个路径是写死的:

    如果改了url函数中的匹配地址,那么使用这个地址的地方不改就出现问题:都要进行修改

    在HTML页面中使用url反向解析:

    那么如果模板中使用的是url反向解析,{% url 'url命名' %} ,Django会根据url命名然后反向解析出它的完整路径,然后渲染在html页面中。这样的话即使你修改掉url函数中的匹配路径,也不需要修改html页面,因为会反向解析出你新改的名字并渲染到页面的链接路径中。

    后面随意加内容都能反向解析成href出来

    根据url的name反向解析获取到url的路径,这样页面中的链接是动态的,而不是写死的,改一下url函数中的路径就要改所有的使用的这个路径。并且它还能往上解析,解析出完整的路径

    那么在视图函数中如何获取到它的反向解析地址呢?

    在django的urls中导入reverse函数

     我们通过reverse('url名称')就能获取到点击博客访问时的路径,

    这个路径是reverse函数帮我们反向解析出来的,而不是从浏览器地址栏的请求url中获取到的。它跟你访问哪个页面没有关系

    如下,访问index页面时使用,打印blog的反向解析路径,reverse是根据url名称反向解析地址,跟你访问哪个页面没有关系,想要哪个url路径就反向解析哪个url名称:

    分组命名中的反向解析:

    有分组命名的反向解析:在url中给url起了别名之后。由于url函数路径中有分组命名,那么需要给这两个地方传递参数才能匹配到这条动态路由,传参数的话只需要我们在模板使用url的tag模板语言方法中按个人意愿传递两个参数就可以实现。根据url别名生成不同的参数

    如果模板页面上使用0开头的数字那么报错,不知原因,但是它似乎将0去掉了,就不能满足是两个数字的条件了:

    如下reverse函数中传递参数。我们如果想用的话,需要传上参数。如果是一个分组,使用reverse获取反向解析路径传参中,元组的传参加个逗号才能表示元组

    我们以上都是为了实现:无论url函数中的地址怎么改,我们都能动态生成,这样后面使用的都是反向解析动态生成的路径,不需要我们一一去改

    我们在模板页面和视图函数reverse函数中使用反向解析并往反向解析的分组中传参,和视图函数从分组传参中获取分组和分组命名传参是分开的两回事。

     我在模板HTML页面使用url反向解析获取blogs的路径,根据app01下的urls中的name找到它的路径有分组命名,我在页面中给分组命名传递参数,然后拼接成一层路径,再往上层找到app01,将完整路径反向解析出来。

    当我get访问这个url地址的时候,后台视图函数能获取到我在模板中传递给分组中的参数,并在视图函数中定义对应形参来接收这个分组参数。

    刚才用的是位置传参,我们还可以使用关键字传参的方法,好处就是不需要按固定的顺序,还能知道传给的是哪个参数。

    在视图函数中接收的分组传参是页面传过来的,打印的是页面的传参生成的反向解析路径,而不是reverse函数传参生成的反向解析路径;在reverse中传参是reverse的,打印的是reverse函数生成反向解析路径,而不是页面传参生成的反向解析路径

    也就是说,分组的反向解析,可以按照位置传参,也可以按照关键字传参

     综上:分两步,第一步给url起个别名,第二步根据url别名去生成一个你想要的完整的路径。

       静态路由的不需要传参数。用到分组和命名分组的话是动态路由,往里面传上相应的参数就可以了。传参的话一种是都有的位置传参,一种是分组命名有的关键字传参。

      模板中使用的话就是url加上别名 (有参数加上参数),生成反向解析的url地址

    重定向使用的是/publiser_list/,现在我的url函数中的路径改成publisher,所有使用/publiser_list/路径的都需要重新修改才能有效,那么我要将它使用url反向解析的方法动态生成路径,这样即使修改了url函数中的路径那么我也不需要再修改代码中使用这个路径的地方了

    反向解析使用场景之一:重定向的使用;

    将之前的重定向路径改成reverse获取的反向解析路径

    没有样式,查看样式没有下载下来。

    在使用Django 项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
    人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
    换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
    获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。
    Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

  • 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
  • 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。
  • 第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。
    在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url模板标签。
  • 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
  • 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。
  • 上面说了一大堆,你可能并没有看懂。(那是官方文档的生硬翻译)。

    咱们简单来说就是可以给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。

    这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL。

    举个简单的例子:

    url(r'^home', views.home, name='home'),  # 给我的url匹配模式起名为 home
    url(r'^index/(\d*)', views.index, name='index'),  # 给我的url匹配模式起名为index

    在模板里面可以这样引用:

    {% url 'home' %}

    在views函数中可以这样引用:

    from django.urls import reverse
    reverse("index", args=("2018", ))

    例子:
    考虑下面的URLconf:

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        # ...
        url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
        # ...
    

    根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/

    你可以在模板的代码中使用下面的方法获得它们:

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    {% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    {% endfor %}
    

    在Python 代码中,这样使用:

    from django.urls import reverse
    from django.shortcuts import redirect
    def redirect_to_year(request):
        # ...
        year = 2006
        # ...
        return redirect(reverse('news-year-archive', args=(year,)))

    如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

    在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

    为了完成上面例子中的URL 反查,你将需要使用命名的URL 模式。URL 的名称使用的字符串可以包含任何你喜欢的字符。不只限制在合法的Python 名称。

    当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。

    在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment

    urlpatterns = [ url(r'^app01/', include('app01.urls', namespace='app01')), url(r'^app02/', include('app02.urls', namespace='app02')),

    app01中的urls.py

    from django.conf.urls import url
    from app01 import views
    app_name = 'app01'
    urlpatterns = [
        url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
    

    app02中的urls.py

    from django.conf.urls import url
    from app02 import views
    app_name = 'app02'
    urlpatterns = [
        url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
    

    现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

    '命名空间名称:URL名称'

    模板中使用:

    {% url 'app01:detail' pk=12 pp=99 %}

    views中的函数中使用

    v = reverse('app01:detail', kwargs={'pk':11})

     这样即使app中URL的命名相同,我也可以反转得到正确的URL了。 

    ---恢复内容结束---

    原文链接:https://www.cnblogs.com/maple-shaw/p/9282718.html

    Django 1.11版本 URLConf官方文档

    URL配置(URLconf)就像Django所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

    我们就是以这种方式告诉Django,遇到哪个URL的时候,要对应执行哪个函数。

    URLconf配置

    基本格式:

    from django.conf.urls import url
    urlpatterns = [
         url(正则表达式, views视图,参数,别名),
    ]
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^articles/2003/$', views.special_case_2003), #前面写个响应地址,跟后面的函数有个对应关系。使用正则表达式跟浏览器地址栏url匹配,匹配上之后才获得后面这个函数
        url(r'^articles/([0-9]{4})/$', views.year_archive), #前面那条路由只能匹配一个,叫静态路由;本条能匹配多个url,叫做动态路由
        url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), #这里的是Django1.1版本的写法
        url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), #url就是一个类,如下图
    

    参数说明:

  • 正则表达式:一个正则表达式字符串
  • views视图:一个可调用对象,通常为一个视图函数
  • 参数:可选的要传递给视图函数的默认参数(字典形式)
  • 别名:一个可选的name参数
  • Django 2.0版本中的路由系统是下面的写法(官方文档):

    from django.urls import path,re_path  #1.0版本的导入类变了
    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),
    

    2.0版本中re_path和1.11版本的url是一样的用法。

    为什么一启动访问的是这个界面,它其实已经做出了匹配了,它匹配访问的地址是/这个路径(http://127.0.0.1:8000/),因为url中没有这个路径,所以是访问不到的。你能访问到的路径它已经在1处显示出来了,照着它写就行了。

    这就是一个静态路由,

    正则表达式详解

    使用正则让它能匹配多个,使用动态路由,再使用blog/就不能找到了。

    需要满足2的正则匹配

    r用来表示转义的,^以什么开头,如果去掉^号,那么前面加上别的内容也能匹配上,后面的能匹配上那它就能匹配成功,这不是我们想要的。加上它就是以blog开头,

  • 每个正则表达式前面的'r' 是可选的但是建议加上。
  • 那么加上表示以四个数字结尾,那么四个数字后面由下面的能匹配

    变成不能成功匹配:

    看下面,我想让它走函数2的,但是访问结果显示的是函数1的:

    匹配有个顺序是从上到下的匹配,先拿1处的和url匹配,匹配上了,就执行了1的函数,它就不会再往下取匹配了。那我们写严谨一点,加上$结尾符号,这样就正确匹配了。因此以后写的时候加个$,防止匹配函数的时候被前面的地址匹配成功而截获了。

  • urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
  • 如果前面第一个的前面加个斜线,那么访问需要添加一个斜线才能访问到页面,因为内部已经给我们加好了。

  • 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  • 当我们不写最后的/的时候,Django给我们做了301重定向了,重新get一次有/的location地址

    而上面那个最后不加斜线然后能做跳转的功能是可以修改的一个配置。默认是True:改为False那么最后不加斜线就404找不到页面了

    # 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项   在setting中添加这个配置
    APPEND_SLASH=True
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^articles/2003/$', views.special_case_2003),
        url(r'^articles/([0-9]{4})/$', views.year_archive),
        url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
        url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
    
  • urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
  • 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
  • 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
  • 每个正则表达式前面的'r' 是可选的但是建议加上。
  • # 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
    APPEND_SLASH=True

    Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。

    其效果就是:

    我们定义了urls.py:

    from django.conf.urls import url
    from app01 import views
    urlpatterns = [
        url(r'^blog/$', views.blog),
    

    访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/ 。

    如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时就会提示找不到页面。

    分组命名匹配

     给正则加个()就是分组,分组之后访问是什么结果呢?报错我们多给了函数一个参数。这是因为分组之后会把分组的内容提出来,并传递给匹配到的函数

    浏览器访问请求匹配到了这条路由,分组将分组中匹配到的内容传递到后面的函数,后面的函数用位置参数接收这个内容,这个内容是url中对应传来的字符串类型数据(捕获的参数永远是字符串)。分组作用就是从url中额外获取一些东西,而且自动将它传递给函数的参数。

    分组作用:将分组的参数按照位置传参传递给视图函数

    我们还可以在url路由中写多个分组,那么函数中就多个参数:

     之前我们直接在url路径上获取参数   id=2这种参数

    那么既然有了分组了能不能把id的包含在路径里面:http://127.0.0.1:8000/blog/1111/22/2/

    那么我们把之前项目出版社的改一下,改成分组的方法:

    修改了之后那后面的就是显示路径了,而不是?拼接的内容了,那么出版社展示页的编辑按钮改成如下:

    而url路由后面就添加\d+,因为你的id是最少一位数的,这样的话我们就能匹配到这里了,但是对应的编辑函数后面需要捕获到请求传过来的这个数,那么需要加括号使用分组,并且我的函数需要位置参数来接收这个分组传过来的内容,因为下面用到的它作为pk,我们直接改形参成pk。并且之前get获取pk的语句可以注释掉了

    修改了之后获取编辑对象没有问题的:

     现在给分组命名,并将之前函数的两个形参删掉,然后报错:  blogs() got an unexpected keyword argument 'year'

    由报错内容可知,分组命名之后应该是将分组内容以关键字形式传递给函数

     添加了两个关键字参数并且关键字和分组命名的名称是一样的,这样就能在视图函数中获取到url传递过来的路径信息了。

    命名分组作用:将命名分组的参数按照关键字传参传递给视图函数

    那么刚才的那个编辑出版社的可以改成命名分组,如下:

    用不用命名分组都可以,建议使用命名分组,这样看到分组命名就知道传的这个参数是什么作用。只是用了分组的话不能看出这个参数是什么

    上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。

    在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。

    在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式。

    下面是以上URLconf 使用命名组的重写:

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^articles/2003/$', views.special_case_2003),
        url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
        url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
        url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
    

    这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。

    例如,针对URL /articles/2017/12/相当于按以下方式调用视图函数:

    views.month_archive(request, year="2017", month="12")

    在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。

    至于究竟应该使用哪一种,你可以根据自己的喜好来决定。

    URLconf匹配的位置

    URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。

    例如,http://www.example.com/myapp/ 请求中,URLconf 将查找 /myapp/ 。

    在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找 /myapp/ 。

    URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POSTGETHEAD等等 —— 都将路由到相同的函数。

    捕获的参数永远都是字符串

    每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

    传递到视图函数views.year_archive() 中的year参数永远是一个字符串类型。

    视图函数中指定默认值

    # urls.py中
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^blog/$', views.page),
        url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
    # views.py中,可以为num指定默认值
    def page(request, num="1"):
    View Code
    

      这里2处用了命名分组,分组的捕获到的内容传递给视图函数。1和2这两个要是一致会出现问题,1是不传参数的,2是多传了一个参数。实际上在3处函数中写的时候是指定了一个默认参数,1匹配到的时候就是不传num值,所以函数就使用num=1的这个值;如果2处page后面捕获了一个2,那么分组命名num会将num=2传递给3处的函数,使得函数使用传递过来的num是2。这样的话那么这两种url匹配上了都不会报错了。不传就用默认的值,传了就用传递的值。一般是用在分页,不传的话显示第一页的内容,博客里面显示你第一页的数据;如果传的话,博客就显示的你传的页码的数据。因此,多个url可以去指定同一个函数,但是你想让它不出问题的话要让他们参数是统一的,可以使用上默认参数。

    在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。

    如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。

    include其他的URLconfs

    根据功能和业务的增多url会越来越多:

    我们需要再开发app,app就能将功能划分开来,app里面写上了不同的业务。如果是多个app的话,一个项目可能不是你一个人在开发,是多个人协同开发。多个人协同开发用什么,可以用git做协同开发。 现在的情况是所有的地址都写在url.py里面。假如是两个人写项目,一个人负责一个app,他们写的路径都写在url.py文件里面,同时编辑一个文件,有人写了这部分,另一个人写了另外一部分。如果某个人不小心把另外一人写的东西删掉了或者两个人写的东西有冲突,那么将来你合并起来的时候是有问题的。那么需要解决冲突的问题。

    用的时候是这样,在功能分类的时候将功能写在app里面了,你的对应关系还写的同一个地方的时候,这个问题也会逐渐的增多,让每人去查找的时候也会很不方便。因此url地址和函数的对应关系应该跟你的app在一块,使用和查找都归这个app,这就需要用到include其它的urlconfs了

    新建一个urls.py在app01中,并将之前项目app01的url剪切到app01下的urls.py文件中,因为导入视图函数模块是当前目录,直接从 . 导入

    那么前端访问过来Django如何知道用哪个urls.py呢,这是根据settings中的配置来的,指定根url配置。由于这个urls可以修改,所以也不一定就是项目settings文件同级目录下的urls文件

    那么指定的根url配置应该如何写呢:

    从模块.conf下的urls导入include
    将第一层的目录匹配成app的名字,匹配到的包含对应app下的urls,这叫包含,也叫路由规划

    这样的话访问的时候它首先让找对应的app,

    不写/还是报错:

    加上/它会提示你后面怎么写:

    后面再写上blog就能访问到了:它是先拿根url配置下的进行匹配,匹配完了再拿后面include的urls再进行匹配,匹配上之后执行include的urls后面对应的函数
    如下:app01就像是一级目录,也就是先找到一级标题app01,再找二级标题blog,二级标题下也可以再写include三级标题,有没有必要写这么复杂的就看你的情况了。

    那么一级标签最后面/不加了,我就访问不到这个路径了

    那么只要把这个/去掉了才能访问:

    之前看的是根url配置中的/不需要我们加,Django帮我们加了。而根url配置中的url和app中的url中间需要一个/需要我们自己添加,要么添加在根url配置的后面,要么添加在app路径的前面,选择一个添加就能正常访问。如果都不加那么它们两个之间没有//才能访问到;如果都加,那么它们两个之间有两个//,那么我们访问也必须写两个//才能访问到。

    组件那里也有include这个同名的方法,tag那里有个inclusion_tag

    #At any point, your urlpatterns can “include” other URLconf modules. This
    #essentially “roots” a set of URLs below other ones.
    #For example, here’s an excerpt of the URLconf for the Django website itself.
    #It includes a number of other URLconfs:
    from django.conf.urls import include, url
    urlpatterns = [
       url(r'^admin/', admin.site.urls),
       url(r'^blog/', include('blog.urls')),  # 可以包含其他的URLconfs文件
    

    传递额外的参数给视图函数(了解)

    url函数中有kwargs,

    那么我们可以在app下urls中添加字典

    如下,这里报错:blog() got an unexpected keyword argument 'year'

    也就是说这里的字典它以关键字参数传递给视图函数

    那么要在视图函数中用app下url函数中传递的字典键值对,我们需要在函数中定义关键字参数的形参。不定义的话会报错,定义的形参不与字典中的键同名会报错

    我们字典中传递的是int,视图函数中接收的就是int类型。而分组命名中的内容,本身路径就是字符串类型,函数中获得的也是字符串类型。

    作用:也就是说我们在url函数中可以使用字典额外的传递一些参数给视图函数。我们也可以不用这样传参数,也可以直接在视图函数中定义默认参数year=2019

    字典传递多个键值对:

     那么我们字典中传递和分组命名一样的关键字参数,那么字典传递的参数优先级要高于分组命名传递的关键字参数。相当于使用字典中update方法,用后面的字典更新掉分组命名中的字典

    URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。

    django.conf.urls.url() 可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
    

    在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。
    当传递额外参数的字典中的参数和URL中捕获值的命名关键字参数同名时,函数调用时将使用的是字典中的参数,而不是URL中捕获的参数。

    命名URL和URL反向解析

    比如视图函数中很多重定向到某个路径(/publiser_list/),那么我们在url函数中将这个路径(^publisher_list/)修改掉(^publisher/),那么视图函数或模板链接中在使用它的地方还需要很麻烦地一一去修改。这样的话视图函数和模板中的这些路径就定死了,不够灵活。这样就用到了URL命名和反向解析

    URL命名,url函数中有个name参数

    给我们的url函数中传递name参数

     我先将根url配置中的app01前缀去掉,让所有的找到app01里面的url,然后在根下直接拼接app01中访问的^index/路径。在index页面中的a标签使用链接是/blog/的路径,

    点击博客能正常跳转到博客页面,但是/blog/这个路径是写死的:

    如果改了url函数中的匹配地址,那么使用这个地址的地方不改就出现问题:都要进行修改

    在HTML页面中使用url反向解析:

    那么如果模板中使用的是url反向解析,{% url 'url命名' %} ,Django会根据url命名然后反向解析出它的完整路径,然后渲染在html页面中。这样的话即使你修改掉url函数中的匹配路径,也不需要修改html页面,因为会反向解析出你新改的名字并渲染到页面的链接路径中。

    后面随意加内容都能反向解析成href出来

    根据url的name反向解析获取到url的路径,这样页面中的链接是动态的,而不是写死的,改一下url函数中的路径就要改所有的使用的这个路径。并且它还能往上解析,解析出完整的路径

    那么在视图函数中如何获取到它的反向解析地址呢?

    在django的urls中导入reverse函数

     我们通过reverse('url名称')就能获取到点击博客访问时的路径,

    这个路径是reverse函数帮我们反向解析出来的,而不是从浏览器地址栏的请求url中获取到的。它跟你访问哪个页面没有关系

    如下,访问index页面时使用,打印blog的反向解析路径,reverse是根据url名称反向解析地址,跟你访问哪个页面没有关系,想要哪个url路径就反向解析哪个url名称:

    分组命名中的反向解析:

    有分组命名的反向解析:在url中给url起了别名之后。由于url函数路径中有分组命名,那么需要给这两个地方传递参数才能匹配到这条动态路由,传参数的话只需要我们在模板使用url的tag模板语言方法中按个人意愿传递两个参数就可以实现。根据url别名生成不同的参数

    如果模板页面上使用0开头的数字那么报错,不知原因,但是它似乎将0去掉了,就不能满足是两个数字的条件了:

    如下reverse函数中传递参数。我们如果想用的话,需要传上参数。如果是一个分组,使用reverse获取反向解析路径传参中,元组的传参加个逗号才能表示元组

    我们以上都是为了实现:无论url函数中的地址怎么改,我们都能动态生成,这样后面使用的都是反向解析动态生成的路径,不需要我们一一去改

    我们在模板页面和视图函数reverse函数中使用反向解析并往反向解析的分组中传参,和视图函数从分组传参中获取分组和分组命名传参是分开的两回事。

     我在模板HTML页面使用url反向解析获取blogs的路径,根据app01下的urls中的name找到它的路径有分组命名,我在页面中给分组命名传递参数,然后拼接成一层路径,再往上层找到app01,将完整路径反向解析出来。

    当我get访问这个url地址的时候,后台视图函数能获取到我在模板中传递给分组中的参数,并在视图函数中定义对应形参来接收这个分组参数。

    刚才用的是位置传参,我们还可以使用关键字传参的方法,好处就是不需要按固定的顺序,还能知道传给的是哪个参数。

    在视图函数中接收的分组传参是页面传过来的,打印的是页面的传参生成的反向解析路径,而不是reverse函数传参生成的反向解析路径;在reverse中传参是reverse的,打印的是reverse函数生成反向解析路径,而不是页面传参生成的反向解析路径

    也就是说,分组的反向解析,可以按照位置传参,也可以按照关键字传参

     综上:分两步,第一步给url起个别名,第二步根据url别名去生成一个你想要的完整的路径。

       静态路由的不需要传参数。用到分组和命名分组的话是动态路由,往里面传上相应的参数就可以了。传参的话一种是都有的位置传参,一种是分组命名有的关键字传参。

      模板中使用的话就是url加上别名 (有参数加上参数),生成反向解析的url地址

    重定向使用的是/publiser_list/,现在我的url函数中的路径改成publisher,所有使用/publiser_list/路径的都需要重新修改才能有效,那么我要将它使用url反向解析的方法动态生成路径,这样即使修改了url函数中的路径那么我也不需要再修改代码中使用这个路径的地方了

    反向解析使用场景之一:重定向的使用;

    将之前的重定向路径改成reverse获取的反向解析路径

    没有样式,查看样式没有下载下来。

    在使用Django 项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
    人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
    换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
    获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。
    Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

  • 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
  • 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。
  • 第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。
    在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url模板标签。
  • 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
  • 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。
  • 上面说了一大堆,你可能并没有看懂。(那是官方文档的生硬翻译)。

    咱们简单来说就是可以给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。

    这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL。

    举个简单的例子:

    url(r'^home', views.home, name='home'),  # 给我的url匹配模式起名为 home
    url(r'^index/(\d*)', views.index, name='index'),  # 给我的url匹配模式起名为index

    在模板里面可以这样引用:

    {% url 'home' %}

    在views函数中可以这样引用:

    from django.urls import reverse
    reverse("index", args=("2018", ))

    例子:
    考虑下面的URLconf:

    from django.conf.urls import url
    from . import views
    urlpatterns = [
        # ...
        url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
        # ...
    

    根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/

    你可以在模板的代码中使用下面的方法获得它们:

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    {% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    {% endfor %}
    

    在Python 代码中,这样使用:

    from django.urls import reverse
    from django.shortcuts import redirect
    def redirect_to_year(request):
        # ...
        year = 2006
        # ...
        return redirect(reverse('news-year-archive', args=(year,)))

    如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

    在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

    为了完成上面例子中的URL 反查,你将需要使用命名的URL 模式。URL 的名称使用的字符串可以包含任何你喜欢的字符。不只限制在合法的Python 名称。

    当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。

    在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment

    如果有两个人,一人开发一个app。两个app中都有各自的urls文件。根url配置中配置app01 home的走app01,app2 home的走app02,各自都能单独访问,并且各自起了相同的url的home名字 

    两个app中有重名的url命名,那么使用url反向解析获取路径的时候获取的是哪个app的呢?

    结果是走的app02下的home
    这个的原因是在url中先给app01下的home起个别名,然后给app02下的home起的别名,这相当于后面的把前面的覆盖掉了。所有在使用url名称的时候使用的是最后面的app02的home别名。

    我们需要的应该是app01和app02下的home都需要,两个app下的相同的url命名在url反向解析的时候要想获得各自正确的地址,那么应该将这两个app下的home区分开来,这就用到了namespace命名空间了。

    在这一个命名空间中起别名,这样隔离开不同的命名空间。也就是app01的都是在app01下起别名,app02的都是在app02下起别名。

    还没有写app01命名空间报错:'app01' is not a registered namespace

    没有指定哪个命名空间下的home报错:Reverse for 'home' not found. 'home' is not a valid view function or pattern name.

     在一级路由中指定命名空间后,在下一级有相同的url命名时,如果有使用反向解析的,需要指定是哪个命名空间下的url名称,冒号隔开,这样url就能正确的反向解析到对应的命名空间,而不是不同命名空间下因为相同的名称而被覆盖前面的命名导致的问题。如果使用了命明空间,那么

    也就是说你用上命名空间的时候,你的使用url反向解析都要加上命名空间

    在函数中使用各自app下的url的名字,也需要加上是哪个命名空间下的。

    urlpatterns = [ url(r'^app01/', include('app01.urls', namespace='app01')), url(r'^app02/', include('app02.urls', namespace='app02')),

    app01中的urls.py

    from django.conf.urls import url
    from app01 import views
    app_name = 'app01'
    urlpatterns = [
        url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
    

    app02中的urls.py

    from django.conf.urls import url
    from app02 import views
    app_name = 'app02'
    urlpatterns = [
        url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
    

    现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

    '命名空间名称:URL名称'

    模板中使用:

    {% url 'app01:detail' pk=12 pp=99 %}

    views中的函数中使用

    v = reverse('app01:detail', kwargs={'pk':11})

     这样即使app中URL的命名相同,我也可以反转得到正确的URL了。 

    书籍、出版社、作者删除三合一案例:

    url这里做了删除了:

    三个删除功能的逻辑相同,如下图:

    需求:那么根据url地址,将三个功能写成一个url地址和一个视图函数

    首先url编写:

    因为我出来要获取是哪个url之外还有获取要删除对象的id,需要添加一个分组

    删除逻辑还是如下,但是要接收两个url地址传参:

    将三个对应的html,跳转地址修改正确:

    然后将试图函数打印一下:

    当浏览器访问匹配的地址的时候,后面打印出传递过来的这两个参数

    models模块,table是字符串,通过反射获取对应的数据表对象,然后对表进行删除。table是传过来的三个类 Publisher Book  Author名的小写,所有用这个方法将首字母变大写。

     页面请求删除的地址

    视图函数中通过分组传参获取到对应的表以及要删除的表记录id

     视图函数中获取到了上面的内容,就可以将对应表记录进行删除:

    给三个首页的url添加url名字

    url名字和我们在页面上捕获的一致, 

     这样的话就能根据删除页面中传参table然后反向解析出三个url中对应用户访问的url的首页了,即有删除按钮的那个页面

     首先设计url地址,地址中有或,动态路由还用到了分组,这样知道你要删除的表,以及表中记录的id

    然后视图函数中通过反射拿到要操作的类,然后对类做操作查到具体的对象做删除

    最后用url反向解析,生成指定的地址,然后重定向到地址。  (用到url反向解析,正则表达式)

    用户访问我们获取的是出版社:

    走到视图函数中table传的就是出版社,通过反射拿到我们的表

    开发功能也是这样。先写一个url地址,一个函数,当写的多了重复性多了再思考能不能优化代码写成一个