Python自动化运维:Django之URL路由

准备
首先新建一个Django 项目

django-admin startproject urlTest

进入manage.py所在目录后

./manage.py startapp app1
./manage.py startpap app2

此时我们新建了一个名为urlTest的项目,其中有两个模块的名称分别为app1和app2。(树目录结构如下)

.
├── app1
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── app2
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── db.sqlite3
├── manage.py
└── urlTest
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

在settings.py中我们可以看到:
ROOT_URLCONF = ‘urlTest.urls‘
#浏览器访问的所有的url都将在urlTest目录下的urls.py中配置,
urls.py默认加入了admin模块的url:

# urlTest.urls.py 
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
]

也即是说,每个url都映射到了一个指定的view函数,其中views中定义的函数接受一个request,并返回一个response。
如对view的工作原理不清楚,可参考这里request-response。

这里写代码片
正则表达式与命名组

首先在app1模块中通过正则表达式分别动态的匹配年,年月,年月日类型的URL。
默认的情况下app1模块中是没有urls.py文件,在我们新建了之后,还需要在urlTest的urls.py加上:

url(r‘^app1/‘, include(‘app1.urls‘))
#这样就包括了app1模块的urls.py文件
接下来在新建的app1模块下的urls.py中写动态正则表达式:

#  app1.urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r‘^$‘, views.index),
    url(r‘^([0-9]{4})/$‘, views.pattern1),
    url(r‘^([0-9]{4})/(0?[1-9]|1[0-2])/$‘, views.pattern2),
    url(r‘^([0-9]{4})/(0?[1-9]|1[0-2])/(0?[1-9]|[1-2][0-9]|3[0-1])/$‘, views.pattern3),
    #记得加上^和$否则年月,年月日的匹配都会被年的匹配
]

我用斜杆“/”作为分割年月日的符号,但是为什么斜杆之前要加上圆括号呢?因为当加上圆括号的时候,django就能从URL中捕获这一个值并传递给相对应的views函数,当然使用的是位置传参。
根据URL匹配到指定的views函数后,我分别返回了HttpResponse:

#  app1.views
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.

def index(request):
    return HttpResponse(‘index‘, ‘text/plain‘)

def pattern1(request, year):
    return HttpResponse(year, ‘text/plain‘)

def pattern2(request, year, month):
    return HttpResponse(year + month, ‘text/plain‘)

def pattern3(request, year, month, date):
    return HttpResponse(year + month + date, ‘text/plain‘)

刚才我们在使用圆括号进行传参的时候是位置传参,那么如果我们希望使用关键字传参的时候该怎么办呢?
这时候我们就使用到了命名组,命名组的正则表达式语法是(?P<name>pattern),其中name是指传递参数的名字,pattern是指匹配模式。
因此,下面的代码与之前的正则表达式+圆括号是完全等效地:

#  app1.urls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r‘^$‘, views.index),
    url(r‘^(?P<year>[0-9]{4})/$‘, views.pattern1),
    url(r‘^(?P<year>[0-9]{4})/(?P<month>0?[1-9]|1[0-2])/$‘, views.pattern2),
    url(r‘^(?P<year>[0-9]{4})/(?P<month>0?[1-9]|1[0-2])/(?P<date>0?[1-9]|[1-2][0-9]|3[0-1])/$‘, views.pattern3),
]

最后值得注意的是在views函数中的参数是可以使用默认参数的,以及可以使用正则表达式进行不捕获参数的设置(可在嵌套参数中使用),如语法(?:….)。
除了捕获URL参数以外,我们还可以直接通过url函数传输额外的数据给view函数。

# urls.py
# 替换index的url
url(r‘^$‘, views.index, {‘string‘: ‘Hello World!‘})

# views.py
def index(request, string):
    return HttpResponse(string, ‘text/plain‘)

如果在包含include函数的url函数里面传输额外的数据,那么额外的数据将传输给被包含的urls.py的每一行url函数上。
URL模式与命名空间

在url patterns上里面的每一个url函数就是一个URL模式,在django中使用类django.core.urlresolvers.RegexURLPattern来表示。

而url patterns就代表着一个URL分解器(url resolver),使用include函数包含其他的url配置模块也是作为一个URL分解器来解析,在django中使用类django.core.urlresolvers.RegexURLResolver来表示。

命名空间主要分为两种,分别是实例命名空间(instance namespace)以及应用命名空间(application namespace)。

为什么需要命名空间呢?
在之前如果我们通过URL反查的话是通过URL模式中的name属性来进行反查标记的,但是name属性容易重复并且不利于复用,当我们要多次部署一个URL配置模块的时候,就无法通过简单的name属性来进行标记了。

如何设置实例命名空间以及应用命名空间?

# include函数的API
include(arg, namespace=None, app_name=None)
# namespace设置实例命名空间,app_name设置应用命名空间
# 不能只设置app_name,否则会报错,以下是报错的源码
if app_name and not namespace:
    raise ValueError(‘Must specify a namespace if specifying app_name.‘)

一般来说,同一应用下的不同实例应该具有相同的应用命名空间,但是,这并不意味着不同应用可以使用相同的实例命名空间,因为实例命名空间在你所有项目中都是唯一的。
URL反向解析

URL反向解析一般是通过reverse函数以及模板中的url标记实现。
我们首先看看在django官方文档中URL反向解析的机制:

    Reversing namespaced URLs
    When given a namespaced URL (e.g. ‘polls:index’) to resolve, Django splits the fully qualified name into parts and then tries the following lookup:

        First, Django looks for a matching application namespace (in this example, ‘polls’). This will yield a list of instances of that application.

        If there is a current application defined, Django finds and returns the URL resolver for that instance. The current application can be specified with the current_app argument to the reverse() function.

        The url template tag uses the namespace of the currently resolved view as the current application in a RequestContext. You can override this default by setting the current application on the request.current_app attribute.

        If there is no current application. Django looks for a default application instance. The default application instance is the instance that has an instance namespace matching the application namespace (in this example, an instance of polls called ‘polls’).

        If there is no default application instance, Django will pick the last deployed instance of the application, whatever its instance name may be.

        If the provided namespace doesn’t match an application namespace in step 1, Django will attempt a direct lookup of the namespace as an instance namespace.

除了最后一个视图名作为name标记来识别,之前的每一个名称首先是作为应用命名空间来识别的(第一条),如果找不到符合的应用命名空间则直接作为实例命名空间来识别(第五条)。
当识别出应用命名空间的时候,再看当前应用有没有定义(即current_app,这里比较容易引起误解,这个当前应用并非应用命名空间,恰恰相反,它是指实例命名空间),如果定义了,直接在之前的已经确认的应用命名空间的所属的实例命名空间列表下寻找current_app的值(第二条)。
如果在实例命名空间列表下找不到current_app的值,那么它会寻找默认的实例命名空间,即名称与应用命名空间相同的实例命名空间。(第三条)
如果连默认的实例命名空间都找不到,那么django会返回最后一个部署的实例命名空间的URL。(第四条)

我们还是通过具体的例子来说明反向解析机制吧。
之前的例子里定义了app1模块和app2模块,再分别生成两个它们的实例。

# urlTest.urls.py
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^app2/first/‘, include(‘app2.urls‘, namespace=‘first‘, app_name=‘app2‘)),
    url(r‘^app2/second/‘, include(‘app2.urls‘, namespace=‘second‘, app_name=‘app2‘)),
    url(r‘^app1/third/‘, include(‘app1.urls‘, namespace="third", app_name=‘app1‘)),
    url(r‘^app1/fourth/‘, include(‘app1.urls‘, namespace="fourth", app_name=‘app1‘)),
]

# app1.views.py
from django.core.urlresolvers import reverse
from django.http import HttpResponse
import pdb
def index(request, string):
    pdb.set_trace()
    return HttpResponse(string, ‘text/plain‘)

在pdb的测试环境下我们使用reverse函数分别确定。

(Pdb) reverse(‘first:index‘)
u‘/app2/first/‘
(Pdb) reverse(‘second:index‘)
u‘/app2/second/‘
(Pdb) reverse(‘third:index‘)
u‘/app1/third/‘
(Pdb) reverse(‘fourth:index‘)
u‘/app1/fourth/‘

我们可以看到,实例命名空间能够唯一确定整个项目的URL。

(Pdb) reverse(‘app1:index‘)
u‘/app1/fourth/‘
(Pdb) reverse(‘app2:index‘)
u‘/app2/second/‘

当我们使用应用命名空间的时候,django反向解析机制在没有提供current_app的情况下又找不到默认的实例命名空间,只能返回最后一个部署的实例命名空间。

(Pdb) reverse(‘app1:index‘, current_app=‘third‘)
u‘/app1/third/‘
(Pdb) reverse(‘app1:index‘, current_app=‘fourth‘)
u‘/app1/fourth/‘
(Pdb) reverse(‘app2:index‘, current_app=‘first‘)
u‘/app2/first/‘
(Pdb) reverse(‘app2:index‘, current_app=‘second‘)
u‘/app2/second/‘

在提供了实例命名空间之后,即使是使用应用命名空间也能唯一确定URL。
最后我们重新添加默认实例命名空间。

# urlTest.urls.py
from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^app2/default/‘, include(‘app2.urls‘, namespace=‘app2‘, app_name=‘app2‘)),
    url(r‘^app2/first/‘, include(‘app2.urls‘, namespace=‘first‘, app_name=‘app2‘)),
    url(r‘^app2/second/‘, include(‘app2.urls‘, namespace=‘second‘, app_name=‘app2‘)),
    url(r‘^app1/default/‘, include(‘app1.urls‘, namespace="app1", app_name=‘app1‘)),
    url(r‘^app1/third/‘, include(‘app1.urls‘, namespace="third", app_name=‘app1‘)),
    url(r‘^app1/fourth/‘, include(‘app1.urls‘, namespace="fourth", app_name=‘app1‘)),
]

# pdb
(Pdb) reverse(‘app1:index‘)
u‘/app1/default/‘
(Pdb) reverse(‘app2:index‘)
u‘/app2/default/‘

最后还要提醒的是,千万不要以为不同应用下可以有相同的实例,namespace必须是unique!

时间: 2024-11-08 18:02:27

Python自动化运维:Django之URL路由的相关文章

Python自动化运维Django入门

随着IT运维技术日益更新,近几年运维自动化越来越火,而且学习python的人非常的火爆,尤其是python自动化运维开发,得到了很多前辈的推崇,尤其是老男孩培训中心.老男孩老师.Alex老师等,在这里非常感谢你们. 这里我也记录一下以前学习Django的一点点心得和方法,方便以后自己查阅,如果能帮助初学者是最好的了!好的,其他不多说了,博文滴走起. 一.系统实战环境 系统版本:CnetOS6.5 x86_64 Django版本:Django-1.5.8 MySQL版本:MySQL-5.1.73

(转)Python自动化运维之13、异常处理及反射(__import__,getattr,hasattr,setattr)

Python自动化运维之13.异常处理及反射(__import__,getattr,hasattr,setattr) 一.异常处理 python异常: python的运行时错误称作异常 (1)语法错误:软件的结构上有错误而导致不能被解释器解释或不能被编译器编译 (2)逻辑错误:由于不完整或不合法的输入所致,也可能是逻辑无法生成.计算或者输出结果需要的过程无法执行等 python异常是一个对象,表示错误或意外情况 (1)在python检测到一个错误时,将触发一个异常 python可以通常异常传导机

Python自动化运维开发活动沙龙(2015-07-11周六)

Python自动化运维开发活动沙龙 2015-07-11(周六) 场地限制,最多仅限50人参加,报名从速! 亲,已是2015年了,做为运维工程师的你还在手动装机器.配服务.看监控.帮开发人肉上线么?还在发愁如何把每天重复的工作自动化起来么?还在想对开源软件进行二次开发定制却无能为力么?还在对开发人员提出的各种无理需求想进行反驳却因为自己不懂开发却被人鄙视么?还在为自己天天努力工作.到处救火却每月只能挣个十来K而感到不爽么? Maybe yes,maybe no! 但是不要不爽了,你的工资不高是因

Python自动化运维课程学习--Day3

本文为参加老男孩Python自动化运维课程第三天学习内容的总结. 大致内容如下: 1.文件操作 2.字符编码转码相关操作 3.函数 0.关于本文中所有运行Python代码的环境: --操作系统:Ubuntu 16.10 (Linux 4.8.0) --Python版本:3.5.2 python2.7.12 --Python IDE: PyCharm 2016.3.2 一.文件操作: 1.文件操作流程:以只读.写(覆盖写).追加写.读写.追加读写.二进制读写等模式打开文件 ==> 得到文件句柄,并

Python自动化运维课程学习--Day2

本文为参加老男孩Python自动化运维课程第二天学习内容的总结. 大致内容如下: 1.python模块初识 2.python程序运行流程 3.python数据类型(只讲了numbers, bool, strings, bytes, list, tuple, dict, set) 4.python数据运算 0.关于本文中所有运行Python代码的环境: --操作系统:Ubuntu 16.10 (Linux 4.8.0) --Python版本:3.5.2 --Python IDE: PyCharm

python自动化运维之路~DAY7

python自动化运维之路~DAY7 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.客户端/服务器架构 C/S 架构是一种典型的两层架构,其全称是Client/Server,即客户端服务器端架构,其客户端包含一个或多个在用户的电脑上运行的程序,而服务器端有两种,一种是数据库服务器端,客户端通过数据库连接访问服务器端的数据:另一种是Socket服务器端,服务器端的程序通过Socket与客户端的程序通信. C/S 架构也可以看做是胖客户端架构.因为客户端需要实现绝大多数的业务

python自动化运维之路~DAY10

python自动化运维之路~DAY10 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

python自动化运维之集中病毒扫描

1.因为我linux的python是2.6.6,所以因为有些模块是2.7的,先进行升级. 步骤地址:http://www.linuxidc.com/Linux/2014-07/104555.htm 2.安装pyclamd yum install -y clamav clamd clamav-update 安装clamavp的相关程序包 chkconfig --level 235 clamd on /usr/bin/freshclam pyClamd-0.3.15.tar.gz安装包安装 3.vi

电子书 Python自动化运维:技术与最佳实践.pdf

本书在中国运维领域将有"划时代"的重要意义:一方面,这是国内一本从纵.深和实践角度探讨Python在运维领域应用的著作:一方面本书的作者是中国运维领域的"偶像级"人物,本书是他在天涯社区和腾讯近10年工作经验的结晶.因为作者实战经验丰富,所以能高屋建瓴.直指痛处,围绕Python自动化运维这个主题,不仅详细介绍了系统基础信息.服务监控.数据报表.系统安全等基础模块,而且深入讲解了自动化操作.系统管理.配置管理.集群管理及大数据应用等高级功能.重要的是,完整重现了4个

云计算开发教程:Python自动化运维开发实战流程控制

今天这篇文章是给大家分享一些云计算开发教程,今天讲解的是:Python自动化运维开发实战流程控制. Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. if 语句用于控制程序的执行,基本形式为: if 判断条件: 执行语句-- else: 执行语句-- 其中"判断条件"成立时(非零),则执行后面的语句,而执行内容可以多行,以缩进来区分表示同一范