URL

概要

我们要在Django项目中为应用程序设计URL,我们可以创建一个名为URLconf(通常为urls.py)的Python模块。
这个模块是纯Python代码,是一个简单的正则表达式到Python函数(视图)之间的映射。

这种映射关系可以很简短也可以很复杂。它还可以引用其他的映射关系。

Django如何处理一个请求

如果用户请求一个由Django提供服务的站点,它将按照以下逻辑决定执行哪些代码:

  1. 通常不考虑中间件的情况下,Django将会确定要使用的根URLconf模块。
  2. Django加载该Python模块并查找变量--urlpatterns,这个变量应该是一个由django.conf.urls.url()实例组成的列表。
  3. Django按照顺序遍历每一个URL模式,并停在与本次请求的URL匹配的第一个URL模式。
  4. 一旦一个正则表达式匹配上用户请求的URL,Django就会导入并调用给定的视图,该视图是一个简单的Python函数(或基于类的视图)。
    该视图将被传入以下参数:
    • 一个请求示例--request
    • 正则表达式中使用分组捕获的值将作为位置参数传递给视图。
    • 正则表达式中的命名分组捕获的值将会以关键字方式传递给视图,但是它可以被直接传参方式覆盖。
  5. 如果没有正则表达式匹配或者在此过程中发生了异常,Django都会调用适当的错误处理视图。

注意:

  1. 分组和命名分组不能同时使用。

    请求URL:
    http://127.0.0.1:8000/kwargs_test/123/abc/

    url(r'^kwargs_test/(\d+)/(?P<name>\w+)/', views.kwargs_test),

    视图:

    def kwargs_test(request, *args, **kwargs):
    print(args, kwargs)
    return HttpResponse("OK")

    输出:

    () {'name': 'abc',}
  2. django.conf.urls.url()的关键字参数会覆盖正则表达式中命名分组捕获的值。

    请求URL:
    http://127.0.0.1:8000/kwargs_test/123/abc/

    url(r'^kwargs_test/(\d+)/(?P<name>\w+)/', views.kwargs_test, {"name1": "Q1mi"}),

    视图:

    def kwargs_test(request, *args, **kwargs):
    print(args, kwargs)
    return HttpResponse("OK")

    输出:

    () {'name': 'abc', 'name1': 'Q1mi'}

小总结:
我们现在掌握了三种向视图函数传递参数的方法:

  1. 在正则匹配模式中使用分组模式从请求的URL中捕获参数并以位置参数的形式传递给视图。
  2. 在正则匹配模式中使用命名分组模式从请求的URL中捕获参数并以关键字参数的形式传递给视图。
  3. 通过给django.conf.urls.url()传递参数。

反向解析URL

在我们的Django项目中,我们经常会遇到要在视图中返回一个重定向到具体URL的响应,或者要将具体的URL地址嵌入到HTML页面中(如:a标签的href属性等)的情况。

我们之前通常都会选择硬编码(写死)的方式来实现类似上述的需求,但是这并不是最优的解决办法。
例如:
在视图函数中:

def add_student(request):
if request.method == "POST":
...
return redirect("/student_list/") # 将URL硬编码到视图中
...

在模板文件的HTML文件中:

<a href="/student_list/">点击查看所有学生信息</a>

Django框架充分考虑了这种需求,所以提供了工具来反向解析(推导)出具体的URL。

name模式

在Django的URLconf中,我们可以通过给匹配模式起别名,然后我们可以通过别名来反向推导出具体的URL。

例如:

在urls.py中:

urlpatterns = [
url(r'^student_list/', views.student_list, name="students"), # 为匹配模式起别名
...
]

在视图中:
通过使用django.urls.reverse根据上面的别名反向推导出URL。

from django.urls import reverse
def add_student(request):
if request.method == "POST":
...
# 根据别名反向推导出具体的URL,避免出现硬编码URL的情况。
url = reverse("students") # 得到URL: /student_list/
return redirect(url)
...

在模板语言的HTML文件中,使用下面的语法来反向推导出URL:

<a href="{% url 'students' %}">点击查看所有学生信息</a>

当我们的匹配模式中的正则表达式有分组或命名分组的时候该怎么办呢?
也就是我们仅仅通过别名无法推导出具体的URL时,该怎么办呢?

我们可以在反向推导URL的时候传递URL中需要的参数:

URL中需要位置参数

例如:
在urls.py中:

urlpatterns = [
# 为匹配模式起别名,并且正则表达式中有分组匹配
url(r'^student/(\d+)', views.student_detail, name="student_detail"),
...
]

像上面的情况,我们就没法简单的通过别名来推导出具体的URL。
我们在反向推导URL的时候就需要传递参数了。

在视图中:
通过使用django.urls.reverse根据上面的别名反向推导出URL。

from django.urls import reverse
def add_student(request):
if request.method == "POST":
...
# 根据别名和位置参数反向推导出具体的URL,避免出现硬编码URL的情况。
url = reverse("student_detail", args=(1,)) # 得到URL:/student/1/
return redirect(url)
...

在模板语言的HTML文件中,使用下面的语法来反向推导出URL:

<a href="{% url 'student_detail' 1 %}">点击查看学生详细信息</a>

URL中需要关键字参数

例如:
在urls.py中:

urlpatterns = [
# 为匹配模式起别名,并且正则表达式中有分组匹配
url(r'^student/(?P<num>\d+)', views.student_detail, name="student_detail"),
...
]

像上面的情况,我们就没法简单的通过别名来推导出具体的URL。
我们在反向推导URL的时候就需要传递参数了。

在视图中:
通过使用django.urls.reverse根据上面的别名反向推导出URL。

from django.urls import reverse
def add_student(request):
if request.method == "POST":
...
# 根据别名和位置参数反向推导出具体的URL,避免出现硬编码URL的情况。
url = reverse("student_detail", kwargs={"num": 10}) # 得到URL:/student/10/
return redirect(url)
...

在模板语言的HTML文件中,使用下面的语法来反向推导出URL:

<a href="{% url 'student_detail' num=10 %}">点击查看学生详细信息</a>

namespace模式

我们可以为每个URL的匹配模式设置一个别名,然后通过别名来反向推导出URL。这样的设置在小型项目也就是URL比较少的情况下是完全够用的。
但是一旦我们的项目比较庞大,其URL可能成百上千,不可避免的会出现别名重复的情况。

这个时候就需要使用namespace了,我们可以为不同的urlpatterns设置一个namespace(命名空间),这样在不同的命名空间下即使别名相同,还是可以通过namespace来区分不同的URL匹配模式。

在urls.py中:

urlpatterns = [
...
# 为app01.urls设置命名空间名:beijing
url(r'^beijing/', include("app01.urls", namespace="beijing")),
# 为app02.urls设置命名空间名:shanghai
url(r'^shanghai/', include("app02.urls", namespace="shanghai")),
...
]

app01/urls.py

urlpatterns = [
# app01/urls.py中有一个别名为index的匹配模式
url(r'^index/$', views.index, name="index"),
]

app02/urls.py

urlpatterns = [
# app02/urls.py中也有一个别名为index的匹配模式
url(r'^index/$', views.index, name="index"),
]

现在我们就可以通过namespace来区分上面两个别名为index的匹配模式来反向推导出准确的URL了。

在视图中:

def index(request):
# 通过 namespce:name 的方式来反向推导出准确的URL
url = reverse("shanghai:index")
...

在模板语言的HTML中:

<a href="{% url 'shanghai:index' %}">上海分公司首页</a>

也可以通过在app/urls.py中定义app_name来设置app级别的namespace

例如:
在上面示例的app01/urls.py文件中:

app_name = "beijing"
urlpatterns = [
url(r'^index/$', views.index, name="index"),
...
]

在这种情况下反向推导URL的语法同上。

Django的URLconf的更多相关文章

  1. django 配置URLconf和获取值

    django中正确配置url匹配找到视图: 1 在项目下的settings.py中ROOT_URLCONF = "项目名.urls" 表示 前台发来请求会先去项目下的test3/u ...

  2. Django框架 之 URLconf

    Django框架 之 URLconf 浏览目录 URL 摘要 Django如何处理一个请求 反向解析URL name模式 namespace模式 一.URL 1.摘要 我们要在Django项目中为应用 ...

  3. [Python] 利用Django进行Web开发系列(二)

    1 编写第一个静态页面——Hello world页面 在上一篇博客<[Python] 利用Django进行Web开发系列(一)>中,我们创建了自己的目录mysite. Step1:创建视图 ...

  4. 【Python】django表单与提交

    参考:http://djangobook.py3k.cn/2.0/chapter07/ 本文的内容应属于django的表单模块,没有涉及到的后端request对象的处理方法可以单独深入学习表单. UR ...

  5. Django视图函数

    一.视图函数 1. 视图函数的第一个参数一定是一个HTTPRequest类型的对象,这个对象是Django自动创建的,具体形参名通常用request.通过这个对象,可以调用请求的一些参数,比如requ ...

  6. django HTTP请求(Request)和回应(Response)对象

    Django使用request和response对象在系统间传递状态.—(阿伦)当一个页面被请示时,Django创建一个包含请求元数据的 HttpRequest 对象. 然后Django调入合适的视图 ...

  7. Django的请求流程(url)

    一.Django是怎么处理请求的? 当你通过在浏览器里敲http://127.0.0.1:8000/hello/来访问Hello world消息得时候,Django在后台有些什么动作呢? 所有均开始于 ...

  8. [R]django的HTTPREQUEST对象

    django的HTTPREQUEST对象 via Django使用request和response对象 当请求一张页面时,Django把请求的metadata数据包装成一个HttpRequest对象, ...

  9. django(二)视图和URL配置

    创建一份视图: 在上一节,使用django-admin.py startproject制作的mysite文件夹中,创建一个叫做views.py的空文件.这个Python模块健柏寒这一章的视图. vie ...

随机推荐

  1. LC 983. Minimum Cost For Tickets

    In a country popular for train travel, you have planned some train travelling one year in advance.  ...

  2. Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result

    Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in 解决方案:$sql = ...

  3. MySQL标准化、自动化部署

    机器标准化:服务器的硬件配置(CPU.硬盘.内存.RAID)要保持一致 目录标准化: mysql的安装目录,存放数据的目录.日志文件等,多台机器上配置要统一 参数标准化: 多台服务器上,存放的my.c ...

  4. python3 高级编程(一) 使用__slots__

    使用__slots__的目的:限制实例的属性 用法:定义class的时候,定义一个特殊的__solts__变量,来限制实例能添加的属性. class Student(object): __slots_ ...

  5. Delphi repeat Until 运用

    procedure TForm3.SpeedButton1Click(Sender: TObject); Var I:integer; begin I:=; repeat I:=I+; ; ShowM ...

  6. Docker 实践备忘录

    平时零散的接触docker,时间久了概念和命令都会忘了,所以集中记下: docker 目标是实现轻量级的操作系统虚拟化解决方案. Docker 的基础是 Linux 容器(LXC)等技术 docker ...

  7. 看看可爱c#中的delegate(委托)和event(事件)用法好不好

    一.开篇忏悔 对自己最拿手的编程语言C#,我想对你说声对不起,因为我到现在为止才明白c#中的delegate和event是怎么用的,惭愧那.好了,那今天就趁月黑风高的夜晚简单来谈谈delegate和e ...

  8. sonar:sonarqube6.7.6与mysql5.7版本不匹配

    问题 更换sonarqube的数据库为mysql后,启动sonarqube,提示Database was upgraded to a more recent of SonarQube. 解决: 将so ...

  9. How To Use Rocketbots As A Dialogflow CRM

    Ever wished you had a CRM for Dialogflow? We did too, so we built one. This is a best practices arti ...

  10. NDK学习笔记-使用现有so动态库

    前面将的都是如何使用C/C++文件生成so动态库,那么在使用别人的so动态库的时候应该怎么做呢?这篇文章就是使用一个变声功能的动态库,完成对于以有so动态库的说明. 动态库来源 在互联网中,有着许许多 ...