sticker0726

 路由分发

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

URLconf 配置的基本格式

from django.conf.urls import url

urlpatterns = [
     url(regex, view,args,name),
]

例子
   url(r\'^index/$\', index_view,{\'foo\': \'bar\'},name=\'main-view\'1),
      url(r\'^index/$\', index_view,{\'foo\': \'bar\'},name=\'main-view2\'),
 

url函数包含4个参数, regex和 views是必须有的, args和name 是可选的

regex: (只需要掌握一些简单的模式就可以了,并不需要称为专家, 特别注意 正则表达式并不能查找Post和GET返回的参数 这里的参数指的是url中? 前面,例如

浏览器发了一个连接为:https://www.example.com/myapp/, 则urlconf将查找myapp/ ,这时浏览器又发来一个连接为https://www.example.com/myapp/?page=3,然而urlconf还是会只查找myapp/) 正则表达式中的的例子也是用了这种方法.

views :视图函数,这个就不过多的解释了

args: 可选参数,,允许你传一些默认参数(字典形式的)给视图函数. 

name:因为:urlpatterns 中有好多url,给你的url()函数起的别名后在你根url中import url时能区分的来

 

正则表达式:

urlpatterns = [
    url(r\'^blog/(\d{4})/(\d{2})\',views.blog_list),#利用正则表达式前端输入的内容,我后端可以取到,但是要分组
]

blog_list函数

from django.shortcuts import HttpResponse
def blog_list(request,*args):
    print(args)
    return HttpResponse("ok")

前端页面输入

http://127.0.0.1:8000/blog/2012/12

后端blog_list函数结果为:

(\'2012\', \'12\')

分组命名

我们为什么要给正则表达式分组?

有时候我们的视图需要url中的部分信息,比如:url(r\'^index/(\d+)\', views.index),我们需要这个url中的数字(\d+),我们就可以把它括起来,视图函数就可以取出这个值,根据*args

如果不分组,后端的args取不到数据,是一个空值,因为他把index/\d+ 全部当成路径了

不分组:

urlpatterns = [
    url(r\'^index/\d+\', views.index),
]

views.py

def index(request):#按位置接收参数
    return HttpResponse(\'this is index\')

 

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

urlpatterns = [
    url(r\'^admin/\', admin.site.urls),
    url(r\'^index/(\d+)\', views.index),
]

views.py

def index(request,args):#按位置接收参数,这个必须有,否则会报错
   ret=Book.objects.get(pk=args)
return HttpResponse(\'this is index\')

 

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

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

前端url为:

 http://127.0.0.1:8050/blog/2012/12

urls.py

urlpatterns = [
    url(r\'^blog/(?P<year>\d{4})/(?P<month>\d{2})\',views.blog_list), 

]

blog_list函数

from django.shortcuts import HttpResponse
def blog_list(request,**kwargs):
    print(kwargs)
    return HttpResponse("ok")

后端blog_list函数结果为:

{\'year\': \'2012\', \'month\': \'12\'}  #这说明是关键字传参,这样我们可以清楚的看到key和value的对应关系了

 范例二:

前端url为:
 http://127.0.0.1:8050/index/11

urls.py

urlpatterns = [
    url(r\'^admin/\', admin.site.urls),
    url(r\'^index/(?P<name>\d+)\', views.index1),
]

views.py

def index1(request,name):#按关键字传参,这里必须是**kwargs或者是name
    print(name)
    return HttpResponse(\'this is index\')

结果:

11

 

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

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

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

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

include

那么什么时候用include()函数?
当有多个App需要路由分配时,但是admin.site.urls是一个例外.如果项目非常庞大,应用非常多,应用的 URL 都写在根 urls.py 配置文件中的话,会显的非常杂乱,
还会出现名称冲突之类的问题这时候就需要用include的了,通过这样的url管理会发现更加整洁,可扩展性更强。


app01.urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r\'index/(\d+)\', views. index),
]
主目录下的urls.py
from django.conf.urls import url,include
from django.contrib import admin
import app01
urlpatterns = [
    url(r\'^admin/\', admin.site.urls),
    url(r\'^app01/\', include(\'app01.urls\')),#可以包含多个app下的urls,
   url(r\'^app02/\', include(\'app02.urls\')),#可以包含多个app下的urls
]

浏览器这样输入:

http://127.0.0.1:8000/app01/index/123/

 

URL命名和URL反向解析

在使用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视图函数和模板中的url不用一个个的变了,它会跟着变

举个简单的例子:

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

这样:

情景一:如果模板中需要跳转到视图函数,可以这样引用:

如果没有参数的话,这样写

<body>

<form action="{% url \'home\' %}" method="post">
{% csrf_token %}
<input type="text" name="user" placeholder="username">
<input type="password" name="pwd" placeholder="password">
<input type="submit" value="提交">
</form>

如果有参数的情况下这样写:

<body>

<form action="{% url \'home\'  参数 %}" method="post">
    {% csrf_token %}
    <input type="text" name="user" placeholder="username">
    <input type="password" name="pwd" placeholder="password">
    <input type="submit" value="提交">
</form>

 

情景二:如果一个视图函数需要要跳到另一个视图函数中可以这样引用:

如果url中有参数 且是无名分组的话,使用位置参数传参,如果是有名分组,使用关键字参数传参

如这样:

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

那么我们视图函数中应该这么写

from django.urls import reverse
def index(request,args):
  ret=reverse("index", args=("2018", )) #注意args这里是一个元组: 如果是有名参数的话,使用关键字传参,且参数的格式: kwargs={\'分组名\' :\'2018\')
  return redirect(ret) #如果这里不用反向解析的话,就应该这样写return redirect("127.0.0.1/index/%s"(args))

 

注意:

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

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

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

做stark项目遇到的反向解析的例子

urls.py

model_name = self.model._meta.model_name #得到model的名字
app_name = self.model._meta.app_label    #得到app的名字
un_list=(app_name,model_name)

urlpatterns = [
         url(r"^$", self.showlist,name="%s_%s_list"%(un_list)),
         url(r"^add/$",self.add,name="%s_%s_add"%(un_list)),
         url(r"^(\d+)/delete/$",self.delete,name="%s_%s_delete"%(un_list)),
         url(r"^(\d+)/change/$", self.change,name="%s_%s_change"%(un_list))
        ]

stark.py中

from django.utils.safestring import mark_safe

from stark.service.sites import site,ModelStark
from .models import Book,Author
from django.urls import reverse
class BookConfig(ModelStark):
    def edit(self,num=None,is_header=False):
        if is_header:
            return "操作"
        model_name = self.model._meta.model_name
        app_name = self.model._meta.app_label
        un_list = (app_name, model_name)
        new_in_list=("%s_%s_change"%(un_list))
        ret = reverse(new_in_list,args=(num,)) #反向解析别忘记参数是一个元组
        return mark_safe("<a href=\'%s\'>编辑</a>"%(ret)) #给前端传一个a标签
    
    list_display=["id","title","price",edit,]
site.register(Book,BookConfig)

命名空间模式

什么情况下会用include?

如果项目非常庞大,应用非常多,应用的 URL 都写在根 urls.py 配置文件中的话,会显的非常杂乱,还会出现名称冲突之类的问题这时候就需要用include的了,通过这样的url管理会发现更加整洁,可扩展性更强。

什么情况下用namespace?

当App01和app02中的url都命名为blog时,这时候,反向解析时就会用上namespace来区分是哪个name,

project中的urls.py

from django.conf.urls import url, include
 
urlpatterns = [
    url(r\'^a/\', include(\'app01.urls\', namespace=\'author-polls\')),
    url(r\'^b/\', include(\'app01.urls\', namespace=\'publisher-polls\')),
]

app中的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\')
]
复制代码

模板中引用:

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

views中的函数中引用,

解析成

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

 

分类:

技术点:

相关文章: