路由定义

路由是客户端访问的url路径与视图函数间的一一映射关系。Django中的路由关系在urls.py文件中,基本格式如下:

urlpatterns = [url(regex,view, kwargs=None, name=None),
]

参数说明:
regex: 匹配url路径的正则表达式,比如r'^login/', 匹配以login/开头的路径,当你在浏览器地址栏输入http://127.0.0.1/login/时,会调用login映射的视图函数来处理请求。几点提醒,
1. 为了避免转义,正则的前面最好加上r
2. 路径前默认都有前导的反斜杠/,我们在正则中就不需要再加了,比如r'login/'就可以,而不用r'^/login/'
3. 如果我们访问127.0.0.1:8000/loginlogin后未加反斜杠/,将会重定向至127.0.0.1:8000/login/,这时因为默认设置APPEND_SLASH = True。另外,任何未在setting.py文件中定义的配置都由django.conf.global_settings 提供
4. 在进行url路径匹配时,只要匹配成功一个,就不在向下匹配。
view: 映射的视图函数
name: 可以为视图函数定义别名,这个稍后介绍。
配置根目录:
我们必须为项目配置根目录,即当用户访问的url不带路径时,必须有相应的视图函数处理并返回响应,而不是错误页面。加入下面的路由:
url(r'^$', view) 当匹配路径为空,调用指定的视图函数处理。

路径分组和视图函数传参

分组是正则中的操作,对正则表达式加括号,就可以实现路径分组。分组的目的是为了给视图函数传参。这里有两种分组方式,通过位置传参的简单分组,和通过关键字传参的命名分组。我们通过下面的栗子来介绍这两种分组方式。
1.新建一个项目learn, 并创建应用calc, 在calc的视图函数中定义一个计算加法的函数add:

from django.http import HttpResponse
# HttpResponse用于直接返回字符串响应
def add(request,a,b):# add 函数除了第一个请求对象参数,还从urls.py中的路由接收另外两个参数用于求和c = int(a) + int(b)return HttpResponse('{a} + {b} = {c}'.format(a=a, b=b, c=str(c)))

2.在项目的urls.py中编辑路由映射:
2.1 简单分组:

from django.conf.urls import url
from django.contrib import admin
from calc import views as calc_viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^add/(\d+)/(\d+)/', calc_views.add),# 简单分组:通过圆括号匹配两组数字,作为参数传给视图函数add
]

2.2 命名分组:

from django.conf.urls import url
from django.contrib import admin
from calc import views as calc_viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^add/(?P<c>\d+)/(?P<b>\d+)/', calc_views.add),# 通过(?P<...>)命名分组, 将分组名a和b传给视图函数add中的关键字参数a和b,# 分组名必须和关键字匹配:如果分组名为x,y 而视图的关键字是a,b,就会报错。
]

3.在浏览器地址栏输入http://127.0.0.1:8000/add/4/5/,你将看到以下结果:

4.另外,如果不用分组,可以通过url中的query string查询字符串来提取数字,进行计算。
因此url需要使用查询字符串形式:
http://127.0.0.1:8000/add/?a=4&b=5
urls路由如下:

urlpatterns = [url(r'^add/$', calc_views.add, name='add'),
]

视图函数中提取查询字符串:

def add(request):a = request.GET.get('a') # get请求中查询字符串以字典键值对的方式封装在request对象中b = request.GET.get('b')c = int(a) + int(b)return HttpResponse('{a} + {b} = {c}'.format(a=a, b=b, c=str(c)))

别名

通过别名还原真实url是很有帮助的,尤其是urls.py路由中的url路径修改后,如果不使用别名,我们就不得不在所有直接使用了url路径的地方一一修改。
比如,在模板的表单提交中,如果action的路径写死了,一旦我们修改了urls.py中的路径,那么客户端的表单提交路径就是无效的,除非我们手动修改action路径。

<form action="path" method="post">

通过使用别名,可以避免这种情况发生。
1.定义别名

urlpatterns = [url(r'^login/$', blog_views.login, name='login')# name='login', 为这条路由起个别名'login', 通过别名可以得到对应的网址
]

2.使用别名:{% url 'name' %}

<form action="{% url 'name' %}" method="post">

还有以一种情况是,用户收藏了我们的旧网址127.0.0.1/index/,现在网站的网址变了127.0.0.1/index_new/,用户如何通过旧网址找到我们的网站。
解决方案是为旧网址写一个跳转函数:
1.编辑视图函数

from django.http import HttpResponseRedirect
from django.urls import reversedef to_new_index(request):return HttpResponseRedirect(reverse(index))# reverse()函数,可以接收一个视图函数,并返回该视图函数对应的url# 返回重定向响应def index(request): # return render(request, 'index.html')

2.编辑路由

from django.conf.urls import url
from blog import views as blog_views
# 从blog应用中导入视图函数urlpatterns = [url(r'^index_new/$', blog_views.index),url(r'^index/$',blog_views.to_new_index),# 如果url路径是/index,那么调用视图函数to_new_index, 跳转至新的url
]

3.这样我们在浏览中输入127.0.0.1/index/,将自动跳转到127.0.0.1/index_new/

路由分发

前面我们都是在项目文件夹的urls.py中通过from app import views这种形式导入视图函数,然后定义具体路由。应该知道的是,项目目录中的urls.py是全局路由,我们要避免将具体应用的路由写在全局路由中,这样会造成代码耦合,而且:1. 当应用越来越多,全局路由将越来越大,不利于维护;2.一旦某一条路由崩溃了,将导致整个路由都崩溃。正确的方式是在每个应用自己的文件夹中定义自己的路由,全局路由只负责做分发。下面我们看一下如何实现。
1.在应用文件夹中新建urls.py,编辑路由规则

from django.conf.urls import url
from . import views
# 从当前文件夹导入视图函数urlpatterns = [url(r'^login/$',views.login, name='login'),url(r'^index/$',views.index, name='index'),
]

2.在全局路由中作分发

from django.conf.urls import url, include   # 导入include函数
from django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# include创建路由分发url(r'^polls/', include('polls.urls')),# 客户端在访问时,只要是属于polls应用的路径,就会被分发到polls应用下的路由
]

注意:
1. 路由分发不能加$结尾约束, 否则直接终止匹配了,造成分发失败。
2. 如果要作一个空路径的默认路由分发,可以通过以下方式:

from django.conf.urls import url, include
from api import urls as api_urls
from web import urls as web_urlsurlpatterns = [url(r'^api/', include(api_urls)), # api开头的分发至api应用的路由url(r'^', include(web_urls))  # 为空,分发至web应用的路由# 路由分发不能加$, 否则终止了
]

这样,我们在浏览器中输入url:http://127.0.0.1:8000/polls/index/,全局路由匹配到是访问polls应用的,将这条url分发到polls下的urls.py来处理。
后续创建了新的应用,就可以定义各自的路由,然后在全局路由中新增一条分发就可以了。

反向路由

reverse

reverse函数可以接收路由中定义的别名或视图函数名,反向生成该视图的url;

导入:from django.shortcuts import reverse

  1. 通过别名反向生成:

    urlpatterns = [url(r'^index/$',views.index, name='index'),
    ]url = reverse('index')
  2. 通过视图函数反向生成:

    def index(request): return render(request, 'index.html')url = reverse(index)
  3. 接收简单分组的参数,args=()

    urlpatterns = [url(r'^add/(\d+)/(\d+)/', view.add, name='add'),
    ]url = reverse(url = reverse('add', args=(2, 9)))
  4. 接收命名分组的参数,kwargs=()

    urlpatterns = [url(r'^add/(?P<a>\d+)/(?P<b>\d+)/', view.add, name='add'),
    ]url = reverse(url = reverse('add', kwargs=(a=2, b=9)))

include路由分发和namespace

在项目的urls.py中经常通过include函数作路由分发,查看源码可以发现include函数的本质返回了一个元组:(urlconf_module, app_name, namespace),urlconf_module是一个个路由组成的列表;还有有一个值是namespace名称空间,它的作用是在别名重复时,作区分用的。因此,如果有名称空间,那么反向路由时需要加名称空间,比如namespace=’xxx’, name=’yyy’,那么通过reverse函数反向路由时,格式为:reverse('xxx:yyy')。如果嵌套了多层名称空间,需要由外到里用冒号:连接起来。

模板中:{% url %}

在模板中,我们可以通过{% url %}配合别名来反向生成url:

  1. 一般形式,通过别名生成:

    {% url 'name' %}
  2. 接收简单分组参数:

    {% url 'name' arg1, arg2 %}
  3. 接收命名分组的参数:

    {% url 'name' arg1=xx, arg2=xx %}

视图函数

视图函数是应用的业务处理逻辑。它接收wsgi封装的客户端请求对象,返回响应。

request请求

request请求对象是视图函数必须接收的第一个参数。通过调用request的属性/方法,可以获取请求信息:
- request.method 获取请求方法(GET/POST)
- request.GET 字典的形式存放GET请求的数据,通过val = request.GET.get(key)可以获取具体的值
- request.POST 字典形式存放POST请求的数据,通过val = request.GET.get(key)可以获取具体的值
- request.META 获取请求的所有元信息,比如获取访问前的地址(执行完某些操作,比如登录后,可利用该地址跳转回去):

next_url = request.META.get('HTTP_REFERER', '/')
  • request.FILE 获取上传的文件

响应方法

  • render(request, 'template', {key: value, ... }) 渲染模板,返回HttpResponse响应。{key:value}称为context上下文对象,key对应模板中的变量名,value对应视图中的对象,渲染时,将视图函数中的对象嵌入模板中。
  • HttpResponse(' ') 字符串对象
  • redirect('path') 重定向,接收的参数是路径。会在响应头中加一个location键,客户端拿到这个键对应的值,即url, 对url发起get请求。

注意redirect和render的区别:
1. 客户端收到redirect重定向响应后,会对重定向的url发起get请求,这时会重走路由映射,调用视图函数。
2. 而render是直接渲染html模板,生成html页面,返回给客户端。

FBV $ CBV

简介

路由分为两种:FBV & CBV

一般我们写的视图函数属于FBV, 请求过来执行视图函数,函数式编程;

而CBV,请求过来,执行的是views.py 中定义的类,面型对象的编程方式;

urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^index.html$', views.IndexView.as_view()), # CBV# 早先的web服务就是提供一个静态HTML页面,不涉及ORM和模板渲染,这里写成这种形式,'^index.html$' 是url伪静态
]

在CBV路由中,要特别注意类名后加as_view()

自定义CBV:

from django.views import View
class IndexView(View): # 自定义的类继承Viewdef get(self,request,*args,**kwargs):return render(request, 'index.html') def post(self,request,*args,**kwargs):return HttpResponse('ok')

请求经过路由到达自定义类后,根据请求方法,来执行get或post函数,这一点是通过反射完成的。查看源码可以看到所有可以反射的方法:

http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
# 如果是通过Ajax发送请求,那么支持以上所以方法

反射操作是在View类中的dispatch方法中完成的:

def dispatch(self, request, *args, **kwargs):if request.method.lower() in self.http_method_names:handler = getattr(self, request.method.lower(), self.http_method_not_allowed)else:handler = self.http_method_not_allowedreturn handler(request, *args, **kwargs)

从以上源码可以看到,请求方法执行结果最终是作为dispatch方法的返回值,因此上面我们自定义的CBA可以写成如下形式:

from django.views import View
class IndexView(View): # 自定义的类继承View# 重用父类中的dispatch方法,并加入自定义逻辑,比如用户验证def dispatch(self, request, *args, **kwargs):if not request.session.get('user-info'):return redirect('/login.html')return super(IndexView, self).dispatch(request,*args,**kwargs)def get(self,request,*args,**kwargs):return render(request, 'index.html')def post(self,request,*args,**kwargs):return HttpResponse('ok')

CBV中使用装饰器

导入:

from django.utils.decorators import method_decorator

三种加装饰的方式:

假设定义了一个装饰器deco:

def deco(func):def wrapper(*args,**kwargs):print('do something')return func(*args,**kwargs)return wrapper
  1. 加到请求方法上:

    class LoginView(View):@method_decorator(deco)def get(self,request):return render(request,'login.html')
  2. 加到dispatch上:

    class LoginView(View):@method_decorator(deco)def dispatch(self, request, *args, **kwargs):return super(LoginView,self).dispatch(request, *args, **kwargs)
  3. 加到类上:

    @method_decorator(deco, name='get') # 指定给get方法加# @method_decorator(deco, name='put')# 必须指定name; 如果有多个方法要装饰,并列写class LoginView(View):def get(self,request):return render(request,'login.html')

我们知道Django的中间件中做了一个全局的csrf保护,但是有时我们希望具体对待,那么可以导入csrf装饰器来实现这个需求:

from django.views.decorators.csrf import csrf_exempt,csrf_protect

其中csrf_exempt是不应用csrf保护;csrf_protect是应用csrf保护;我们就可以根据需要加到具体的视图上了:

@csrf_protect
def demo(request):print('DEMO')return HttpResponse('ok')

但是,在目前的Django版本中要注意,如果是CBV,那么csrf装饰器只能加在类中的dispatch方法上:

class LoginView(View):@method_decorator(csrf_exempt)def dispatch(self, request, *args, **kwargs):return super(LoginView,self).dispatch(request, *args, **kwargs)

Django(二) 路由和视图相关推荐

  1. Django路由与视图

    路由层 一.路由匹配规则: 第一个参数是正则表达式,匹配规则按照从上往下一次匹配,匹配到一个之后立即匹配,直接执行对应的视图函数 url(r'login', views.login), 如果按上面的形 ...

  2. Django之路由层、视图层、模板层介绍

    一.Django请求生命周期 1.路由层urls.py Django 1.11版本 URLConf官方文档 1.1 urls.py配置基本格式 from django.conf.urls import ...

  3. Django基础三之视图函数

    Django基础三之视图函数 一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML ...

  4. 13.Django之view初探视图函数(一)

    一.什么是视图函数? Django框架中的视图函数其实就是个普通的python函数,这个函数可以接收web请求,并且返回web响应. 视图函数响应给客户端浏览器的内容,可以是一个html文档,还可以是 ...

  5. day 53-1 Django基础三之视图函数

    Django基础三之视图函数 本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Djang ...

  6. django之路由(url)

    前言: Django大致工作流程 1.客户端发送请求(get/post)经过web服务器.Django中间件. 到达路由分配系统  2.路由分配系统根据提取 request中携带的的url路径(pat ...

  7. Django框架--路由分配系统

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...

  8. Django之路由层

    天行健,君子以自强不息 -周易 文章目录 路由层 一.路由层之路由匹配 1.什么是路由 2.路由匹配 URL( )方法 基本格式: 参数介绍: regex: view: kwargs name 示例: ...

  9. django框架——路由系统(正则表达式)

    一.路由系统基本格式: urlpatterns = [path( 要匹配的路径(可以是正则表达式), 视图函数, 参数, 别名)] 参数说明: 正则表达式:一个正则表达式字符串 视图函数:一个可调用对 ...

  10. Django的路由系统

    Django的路由系统 url配置就像Django所支撑网站的目录.它的本质是url与要为url调用的试图函数之间的映射表. 我们就是以这种方式告诉Django,遇到哪个URL的时候,要应对执行哪个函 ...

最新文章

  1. HTTP长连接服务器端推技术
  2. Bind 配置非递归服务器
  3. Python计算机视觉:第十章 OpenCV
  4. java根据pdf模板生成pdf_Java 复制、压缩PDF文档
  5. Spring MVC 学习笔记 json格式的输入和输出
  6. 测试常用工具下载地址,LR11、QC11
  7. Java中多线程访问冲突的解决方式
  8. Swagger天天用,但它背后的实现原理很多人都不知道!
  9. VS2010“.NET研究”中的调试技巧
  10. jsp实现简单购物车页面
  11. c# MessageBox 用法大全
  12. 模拟数据生成工具--Faker
  13. 前端架构设计第四课 Babel构建公共库实战
  14. distpicker初始化以及设定指定值
  15. [教程]VNR添加游戏以及H特殊码的使用
  16. VB调用摄像头录像,拍照,保存
  17. 乔布斯:这九本书每个人都该读一读
  18. 你理解的商业数据分析到底是怎样的?
  19. iOS 15:Spotlight 搜索中的所有新功能
  20. 【硬见小百科】SMT工艺,是什么影响锡膏印刷的质量

热门文章

  1. (王道408考研数据结构)第五章树-第四节3:哈夫曼树基本概念、构造和哈夫曼编码
  2. Linux系统编程16:进程控制之进程终止以及终止进程的三种情况
  3. Java 网络实例二(查看主机指定文件的最后修改时间、Socket实现多线程服务器程序、Socket连接到指定主机、网页抓取)
  4. Tcpdump个人实战总结
  5. win32diskimager报错:An error occured when attempting to XXX, Error 5: Access is Denied
  6. C/C++:Windows编程—Hook IE浏览器实现URL拦截及更改(上)
  7. 为Get/Post课程收集资料
  8. 进程与multiprocessing模块
  9. spring 国际化-i18n
  10. 3D Game Programming with directx 11 习题答案 8.3