Django中URL视图函数的一些高级概念介绍


Posted in Python onJuly 20, 2015

说到关于请求方法的分支,让我们来看一下可以用什么好的方法来实现它。 考虑这个 URLconf/view 设计:

# urls.py

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
  # ...
  (r'^somepage/$', views.some_page),
  # ...
)

# views.py

from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render_to_response

def some_page(request):
  if request.method == 'POST':
    do_something_for_post()
    return HttpResponseRedirect('/someurl/')
  elif request.method == 'GET':
    do_something_for_get()
    return render_to_response('page.html')
  else:
    raise Http404()

在这个示例中,`` some_page()`` 视图函数对`` POST`` 和`` GET`` 这两种请求方法的处理完全不同。 它们唯一的共同点是共享一个URL地址: `` /somepage/.``正如大家所看到的,在同一个视图函数中对`` POST`` 和`` GET`` 进行处理是一种很初级也很粗糙的做法。 一个比较好的设计习惯应该是,用两个分开的视图函数——一个处理`` POST`` 请求,另一个处理`` GET`` 请求,然后在相应的地方分别进行调用。

我们可以像这样做:先写一个视图函数然后由它来具体分派其它的视图,在之前或之后可以执行一些我们自定的程序逻辑。 下边的示例展示了这个技术是如何帮我们改进前边那个简单的`` some_page()`` 视图的:

# views.py

from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render_to_response

def method_splitter(request, GET=None, POST=None):
  if request.method == 'GET' and GET is not None:
    return GET(request)
  elif request.method == 'POST' and POST is not None:
    return POST(request)
  raise Http404

def some_page_get(request):
  assert request.method == 'GET'
  do_something_for_get()
  return render_to_response('page.html')

def some_page_post(request):
  assert request.method == 'POST'
  do_something_for_post()
  return HttpResponseRedirect('/someurl/')

# urls.py

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
  # ...
  (r'^somepage/$', views.method_splitter, {'GET': views.some_page_get, 'POST': views.some_page_post}),
  # ...
)

让我们从头看一下代码是如何工作的:

    我们写了一个新的视图,`` method_splitter()`` ,它根据`` request.method`` 返回的值来调用相应的视图。可以看到它带有两个关键参数,`` GET`` 和`` POST`` ,也许应该是* 视图函数* 。如果`` request.method`` 返回`` GET`` ,那它就会自动调用`` GET`` 视图。 如果`` request.method`` 返回的是`` POST`` ,那它调用的就是`` POST`` 视图。 如果`` request.method`` 返回的是其它值(如:`` HEAD`` ),或者是没有把`` GET`` 或`` POST`` 提交给此函数,那它就会抛出一个`` Http404`` 错误。

    在URLconf中,我们把`` /somepage/`` 指到`` method_splitter()`` 函数,并把视图函数额外需要用到的`` GET`` 和`` POST`` 参数传递给它。

    最终,我们把`` some_page()`` 视图分解到两个视图函数中`` some_page_get()`` 和`` some_page_post()`` 。这比把所有逻辑都挤到一个单一视图的做法要优雅得多。

    注意,在技术上这些视图函数就不用再去检查`` request.method`` 了,因为`` method_splitter()`` 已经替它们做了。 (比如,`` some_page_post()`` 被调用的时候,我们可以确信`` request.method`` 返回的值是`` post`` 。)当然,这样做不止更安全也能更好的将代码文档化,这里我们做了一个假定,就是`` request.method`` 能象我们所期望的那样工作。

现在我们就拥有了一个不错的,可以通用的视图函数了,里边封装着由`` request.method`` 的返回值来分派不同的视图的程序。关于`` method_splitter()`` 就不说什么了,当然,我们可以把它们重用到其它项目中。

然而,当我们做到这一步时,我们仍然可以改进`` method_splitter`` 。从代码我们可以看到,它假设`` Get`` 和`` POST`` 视图除了`` request`` 之外不需要任何其他的参数。那么,假如我们想要使用`` method_splitter`` 与那种会从URL里捕捉字符,或者会接收一些可选参数的视图一起工作时该怎么办呢?

为了实现这个,我们可以使用Python中一个优雅的特性 带星号的可变参数 我们先展示这些例子,接着再进行解释

def method_splitter(request, *args, **kwargs):
  get_view = kwargs.pop('GET', None)
  post_view = kwargs.pop('POST', None)
  if request.method == 'GET' and get_view is not None:
    return get_view(request, *args, **kwargs)
  elif request.method == 'POST' and post_view is not None:
    return post_view(request, *args, **kwargs)
  raise Http404

这里,我们重构method_splitter(),去掉了GET和POST两个关键字参数,改而支持使用*args和和**kwargs(注意*号) 这是一个Python特性,允许函数接受动态的、可变数量的、参数名只在运行时可知的参数。 如果你在函数定义时,只在参数前面加一个*号,所有传递给函数的参数将会保存为一个元组. 如果你在函数定义时,在参数前面加两个*号,所有传递给函数的关键字参数,将会保存为一个字典

例如,对于这个函数

def foo(*args, **kwargs):
  print "Positional arguments are:"
  print args
  print "Keyword arguments are:"
  print kwargs

看一下它是怎么工作的

>>> foo(1, 2, 3)
Positional arguments are:
(1, 2, 3)
Keyword arguments are:
{}
>>> foo(1, 2, name='Adrian', framework='Django')
Positional arguments are:
(1, 2)
Keyword arguments are:
{'framework': 'Django', 'name': 'Adrian'}

回过头来看,你能发现我们用method_splitter()和*args接受**kwargs函数参数并把它们传递到正确的视图。any 但是在我们这样做之前,我们要调用两次获得参数kwargs.pop()GETPOST,如果它们合法的话。 (我们通过指定pop的缺省值为None,来避免由于一个或者多个关键字缺失带来的KeyError)

Python 相关文章推荐
Python中条件选择和循环语句使用方法介绍
Mar 13 Python
python实现对一个完整url进行分割的方法
Apr 29 Python
python同时给两个收件人发送邮件的方法
Apr 30 Python
python爬取51job中hr的邮箱
May 14 Python
python中利用zfill方法自动给数字前面补0
Apr 10 Python
解决新django中的path不能使用正则表达式的问题
Dec 18 Python
python实现kNN算法识别手写体数字的示例代码
Aug 16 Python
python 协程中的迭代器,生成器原理及应用实例详解
Oct 28 Python
python实现操作文件(文件夹)
Oct 31 Python
Python3 中作为一等对象的函数解析
Dec 11 Python
python属于解释型语言么
Jun 15 Python
OpenCV4.1.0+VS2017环境配置的方法步骤
Jul 09 Python
Python的Django框架中从url中捕捉文本的方法
Jul 20 #Python
Django框架中处理URLconf中特定的URL的方法
Jul 20 #Python
在Django中创建URLconf相关的通用视图的方法
Jul 20 #Python
python通过socket查询whois的方法
Jul 18 #Python
Python字符串匹配算法KMP实例
Jul 18 #Python
Python通过正则表达式选取callback的方法
Jul 18 #Python
Django的URLconf中使用缺省视图参数的方法
Jul 18 #Python
You might like
基于在生产环境中使用php性能测试工具xhprof的详解
2013/06/03 PHP
PHP检测字符串是否为UTF8编码的常用方法
2014/11/21 PHP
WebGame《逆转裁判》完整版 代码下载(1月24日更新)
2007/01/29 Javascript
JQuery 插件制作实践 xMarquee插件V1.0
2010/04/02 Javascript
判断JS对象是否拥有某种属性的两种方式
2013/12/02 Javascript
js中array的sort()方法使用介绍
2014/02/20 Javascript
使用javascript提交form表单方法汇总
2015/06/25 Javascript
JavaScript取得键盘按下方向键是哪个的方法
2015/08/04 Javascript
javascript中对变量类型的判断方法
2015/08/09 Javascript
使用控制台破解百小度一个月只准改一次名字
2015/08/13 Javascript
js数组常见操作及数组与字符串相互转化实例详解
2015/11/10 Javascript
jQuery滚动监听实现商城楼梯式导航效果
2017/03/06 Javascript
NodeJS、NPM安装配置步骤(windows版本) 以及环境变量详解
2017/05/13 NodeJs
基于Bootstrap框架菜鸟入门教程(推荐)
2017/09/17 Javascript
Vue 中的受控与非受控组件的实现
2018/12/17 Javascript
小程序实现人脸识别功能(百度ai)
2018/12/23 Javascript
vue框架下部署上线后刷新报404问题的解决方案(推荐)
2019/04/03 Javascript
[50:15]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
python3实现短网址和数字相互转换的方法
2015/04/28 Python
Python编码类型转换方法详解
2016/07/01 Python
python交换两个变量的值方法
2019/01/12 Python
python 中值滤波,椒盐去噪,图片增强实例
2019/12/18 Python
关于win10在tensorflow的安装及在pycharm中运行步骤详解
2020/03/16 Python
处理HTML5新标签的浏览器兼容版问题
2017/03/13 HTML / CSS
使用phonegap播放音频的实现方法
2017/03/31 HTML / CSS
美国标志性加大尺码时装品牌:Ashley Stewart
2016/12/15 全球购物
GANT英国官方网上商店:甘特衬衫
2018/02/06 全球购物
Allsole美国/加拿大:英国一家专门出售品牌鞋子的网站
2018/10/21 全球购物
澳大利亚二手奢侈品网站:Modsie
2019/09/23 全球购物
Aurora London官网:奢华、负担得起的皮革手袋
2020/08/01 全球购物
什么是Rollback Segment
2013/04/22 面试题
九年级英语教学反思
2014/01/31 职场文书
继承公证书样本
2014/04/04 职场文书
2014年公务员转正工作总结
2014/11/07 职场文书
寒山寺导游词
2015/02/03 职场文书
2015年营销工作总结范文
2015/04/23 职场文书