Django 1.6 基于类的通用视图

  最初 django 的视图都是用函数实现的,后来开发出一些通用视图函数,以取代某些常见的重复性代码。通用视图就像是一些封装好的处理器,使用它们的时候只须要给出特定的参数集即可,不必关心具体的实现。各种通用视图的参考参见:https://docs.djangoproject.com/en/1.6/ref/class-based-views/然后函数式视图的缺点——难以扩展和自定义,开始显现出来。于是 1.3 起 django 开始用类视图来实现通用视图。较于函数,类能够更方便的实现继承和 mixins。但类视图并非要取代函数视图,这从现在 URLConf 仍然保留着函数式的调用方式便可以看出来。因为 URLConf 仍然使用“给一个可调用对象传入 HttpRequest ,并期待其返回一个 HttpResponse”这样的逻辑,所以对于类视图,必须设计一个可调用的接口。这就是类视图的 as_view() 类方法。他接受 request,并实例化类视图,接着调用实例的 dispatch() 方法。这个方法会依据 request 的请求类型再去调用实例的对应同名方法,并把 request 传过去,如果没有对应的方法,就引发一个 HttpResponseNotAllowed 异常。(可以捕捉这个异常用以返回一个 404)值得注意的是,这个(比如 get)方法的返回值和普通的视图函数的返回值没有什么不同,这意味着,http shortcuts(render_to_response之类的)和 TemplateResponse 在类视图里也是有效的。

  django 提供了一系列现成的类视图,他们都继承自一个 View 基类(django.views.generic.base.View)。在这个基类里实现了与 URLs 的接口(as_view)、请求方法匹配(dispatch)和一些其他的基本功能。比如 RedirectView 实现了一个简单的 HTTP 重定向,TemplateView 给 View 添加了一个渲染模板的功能。

简单用法:

  最简单的通用视图用法就是直接在 URLConf 里创建他们。如果你只需要改几个类视图的属性的话,你可以直接把他们当做关键字参数传入视图的 as_view() 方法里。任何传入 as_view() 的参数都会覆盖类视图实例里的同名属性。

  1. from django.conf.urls import patterns
  2. from django.views.generic import TemplateView
  3. urlpatterns = patterns('',
  4. (r'^about/',TemplateView.as_view(template_name="about.html")),
  5. )

子类化通用视图:

  一种稍微高级点的使用通用视图的方法是子类化他们,并重写必要的属性(比如 template_name)和方法(比如 get_context_data)。举个栗子,一个 AboutView,他覆盖了 TemplateView 的模板属性和获取 Context 方法(这是使用 TemplateView 的一般做法):

  1. # some_app/views.py
  2. from django.views.generic import TemplateView
  3. class AboutView(TemplateView):
  4. template_name = "about.html"
  5. def get_context_data(self, **kwargs):
  6. # alter context return context
  7. context = super().get_context_data(**kwargs)

对应的 URLConf:

  1. # urls.py
  2. from django.conf.urls import patterns
  3. from some_app.views import AboutView
  4. urlpatterns = patterns('',
  5. (r'^about/', AboutView.as_view()),
  6. )

  这里的 get_context_data(self,**kwargs) 方法只接受关键字参数,是因为这个参数来自于 URLConf 的第三个参数(这例子里没用到),而这个参数就是一个关键字参数。另外,如果想要对 context 做某些额外的处理,比如增加一些变量,那么就应该把代码写在调用了父类的 get_context_data 之后,return context 之前。上面这个例子对通用视图的好处体现的还不明显(TemplateView 比 render_to_response 强不到哪去),通用视图的优势常常体现在对数据库的访问上,比如下面这个 显示对象列表的视图,完全省去了对数据库的操作:

  1. # views.py
  2. from django.views.generic import ListView
  3. from books.models import Publisher
  4. class PublisherList(ListView):
  5. model = Publisher
  6. # urls.py
  7. from django.conf.urls import patterns, url
  8. from books.views import PublisherList
  9. urlpatterns = patterns('',
  10. url(r'^publishers/$', PublisherList.as_view()),
  11. )
  12. #ListView 会用到的模板:
  13. { % extends "base.html" % }
  14. { % block content % }
  15. < h2 > Publishers < /h2 >
  16. <ul >
  17. { % for publisher in object_list % }
  18. < li > {{ publisher.name }} < /li >
  19. { % endfor % }
  20. < /ul >
  21. { % endblock % }

template contexts 的变量名匹配:

  上例中,在 publisher_list.html 模板中使用的 context 变量名为“object_list”。这是一个通用名,即 ListView 视图总会使用的一个名字,另外当你访问的是一个数据库模型的时候,比如上例中的 Publisher,视图还会自动用小写的模型名+_list 的格式命名一个相同的 context 去渲染模板,即“publisher_list”。所以上例中和其他对模型的访问都可以用这种格式的名字来编写模板。如果对此种匹配方式仍不放心,还可以在通用视图中显式指定 context 的名字,就像这样(建议总是显示指定):

  1. # views.py
  2. from django.views.generic import ListView
  3. from books.models import Publisher
  4. class PublisherList(ListView):
  5. model = Publisher
  6. context_object_name = 'my_favourite_publishers'

对数据模型进行筛选:

  通过 model = Publisher 这样的方式可以指定通用视图使用的模型,而当想要对模型的 objects 管理器应用 filter 的时候,可以通过 query_set 变量来指定:

  1. from django.views.generic import ListView
  2. from books.models import Book
  3. class BookList(ListView):
  4. queryset = Book.objects.order_by('-publication_date')
  5. context_object_name = 'book_list'

而如果 filter 的参数来自于 url 匹配出的子组,那么这个参数将被传入类视图的 self.args 和 self.kwargs 属性内。get_queryset() 方法也可以用来做逻辑性更强的定制:

  1. # urls.py
  2. from django.conf.urls import patterns
  3. from books.views import PublisherBookList
  4. urlpatterns = patterns('',
  5. (r'^books/([\w-]+)/$', PublisherBookList.as_view()),
  6. )
  7. # views.py
  8. from django.shortcuts import get_object_or_404
  9. from django.views.generic import ListView
  10. from books.models import Book, Publisher
  11. class PublisherBookList(ListView):
  12. template_name = 'books/books_by_publisher.html'
  13. def get_queryset(self):
  14. self.publisher = get_object_or_404(Publisher,name=self.args[0])
  15. return Book.objects.filter(publisher=self.publisher)

实现模型访问时的额外小动作:

  如果想要在对数据库进行访问之前(或后)实现一些额外的操作,那么可以通过封装 类视图的 get_object() 方法来实现。

例:假设 Author 模型有一个 DateTimeField 类型的字段,名为 last_accessed,用以保存最后一次被访问的时间。

  1. # models.py
  2. from django.db import models
  3. class Author(models.Model):
  4. salutation = models.CharField(max_length=10)
  5. name = models.CharField(max_length=200)
  6. email = models.EmailField()
  7. headshot = models.ImageField(upload_to='author_headshots')
      last_accessed = models.DateTimeField()
  8.  
  9. #URLConf
  10. from django.conf.urls import patterns, url
  11. from books.views import AuthorDetailView
  12. urlpatterns = patterns('',
      url(r'^authors/(?P<pk>\d+)/$', AuthorDetailView.as_view(), name='author-detail'),
    )
  13.  
  14. #View
  15. from django.views.generic import DetailView
  16. from django.utils import timezone
  17. from books.models import Author
  18.  
  19. class AuthorDetailView(DetailView):
  20.   queryset = Author.objects.all()
  21.   def get_object(self):
  22.     # Call the superclass
        object = super(AuthorDetailView, self).get_object()
        # Record the last accessed date
        object.last_accessed = timezone.now()
        object.save()
        # Return the object
        return object

此处 URL 里的 pk 是 DetailView 视图默认使用的某个名字,详情可参考视图的细节页面。

对 HTTP require method 的支持:

为不同的请求写一个同名的方法就可以了,调用工作会有 dispatch() 方法来做。比如:

  1. # urls.py
  2. from django.conf.urls import patterns
  3. from myapp.views import MyView
  4. urlpatterns = patterns('',
  5. (r'^about/', MyView.as_view()),
  6. )
  7. from django.http import HttpResponse
  8. from django.views.generic import View
  9. class MyView(View):
  10. def get(self, request):
  11. # <view logic>
  12. return HttpResponse('result')

还可以定义一些 head() , post() 之类的方法。这种方式取代了视图函数里的 if 分支逻辑。

处理 Form:

基本 Forms:

一个简单的 contact form

  1. # forms.py
  2. from django import forms
  3. class ContactForm(forms.Form):
  4. ef send_email(self):
  5. # 使用 self.cleaned_data 字典来发送一封邮件 pass

对应的视图可以使用 FormView 构建:

  1. # views.py
  2. from myapp.forms import ContactForm
  3. from django.views.generic.edit import FormView
  4. class ContactView(FormView):
  5. template_name = 'contact.html'
  6. form_class = ContactForm
  7. success_url = '/thanks/' def
  8. form_valid(self, form):
  9. # 当有效的数据被 POST 进来以后,本方法就会被调用
  10. # 本方法应当返回一个
  11. HttpResponse.form.send_email()
  12. return super(ContactView, self).form_valid(form)

注意:

  • FormView 继承自 TemplateResponseMixin,所以 template_name 属性可用
  • form_valid() 的默认实现仅仅是将页面重定向至 success_url

转载于:http://m.oschina.net/blog/214898

Django 1.6 基于类的通用视图的更多相关文章

  1. Django——django1.6 基于类的通用视图

    最初 django 的视图都是用函数实现的,后来开发出一些通用视图函数,以取代某些常见的重复性代码.通用视图就像是一些封装好的处理器,使用它们的时候只须要给出特定的参数集即可,不必关心具体的实现.各种 ...

  2. Django 基于类的通用视图

    在早期,我们认识到在视图开发过程中有共同的用法和模式.这时我们引入基于函数的通用视图来抽象这些模式以简化常见情形的视图开发. 基于函数视图的用法有以下三种: def index(request): r ...

  3. 用基于类的通用视图处理表单(Class-based generic views)

    处理表单通常包含3步: 初始化GET(空白的后者预填充的表单) POST非法数据(通常重新显示带有错误信息的表单) POST合法数据(提交数据并重定向) 为了将你从这些烦人的重复步骤中解救出来,Dja ...

  4. 基于类的通用视图(Class-based generic views)

    在web开发中,最令人头痛的就是一遍又一遍的重复固定的模式.在解决了模板层面和模型层面的重复代码之痛之后,Django使用通用视图来解决视图层面的代码重复. 扩展通用视图 毫无疑问通用视图可以大幅度地 ...

  5. Django:之Sitemap站点地图、通用视图和上下文渲染器

    Django中自带了sitemap框架,用来生成xml文件 Django sitemap演示: sitemap很重要,可以用来通知搜索引擎页面的地址,页面的重要性,帮助站点得到比较好的收录. 开启si ...

  6. Django初级手册4-表单与通用视图

    表单的编写 1. detail.html模版的编写 <h1>{{ poll.question }}</h1> {% if error_message %}<p>&l ...

  7. Django——基于类的视图(class-based view)

    刚开始的时候,django只有基于函数的视图(Function-based views).为了解决开发视图中繁杂的重复代码,基于函数的通用视图( Funcation-based generic vie ...

  8. django通用视图(类方法)

    这周是我入职的第一周,入职第一天看到嘉兴大佬的项目代码.视图中有类方法,我感到很困惑. 联想到之前北京融360的电话面试,问我有无写过类方法……看来有必要了解下视图的类方法,上网搜了很多,原来这就是所 ...

  9. 介绍——基于类的视图(class-based view)

    ​刚开始的时候,django只有基于函数的视图(Function-based views).为了解决开发视图中繁杂的重复代码,基于函数的通用视图( Class-based generic views) ...

随机推荐

  1. Mysql 建表时,日期时间类型选择

    mysql(5.5)所支持的日期时间类型有:DATETIME. TIMESTAMP.DATE.TIME.YEAR. 几种类型比较如下: 日期时间类型 占用空间 日期格式 最小值 最大值 零值表示  D ...

  2. 提高MySQL数据库查询效率的几个技巧(转载)

    [size=5][color=Red]提高MySQL数据库查询效率的几个技巧(转)[/color][/size]      MySQL由于它本身的小巧和操作的高效, 在数据库应用中越来越多的被采用.我 ...

  3. php 实现同一个账号同时只能一个人登录

    php 实现同一个账号同时只能一个人登录 张映 发表于 2015-01-22 分类目录: php 标签:mysql, nginx, openfire, php, redis 以前考虑过这个问题,今天实 ...

  4. ACM题目推荐(刘汝佳书上出现的一些题目)[非原创]

    原地址:http://blog.csdn.net/hncqp/article/details/1758337 推荐一些题目,希望对参与ICPC竞赛的同学有所帮助. POJ上一些题目在http://16 ...

  5. wordpress教程之文章页single.php获取当前文章所属分类

    之所以要发这篇文章,是因为这个方法适用于: WP默认文章分类 手动添加的自定文章分类 插件(custom post type ui)添加的自定义文章分类(含taxonomy) 方法目的:在文章模板中, ...

  6. Linux下find与grep指令的相关用法

    find命令 find命令的一般形式 find命令的常用选项及实例 find与xargs grep命令 grep命令的一般形式 grep正则表达式元字符集(基本集) grep命令的常用选项及实例 1. ...

  7. 你真的会玩SQL吗?透视转换

    原文:你真的会玩SQL吗?透视转换 透视转换是一种行列互转的技术,在转过程中可能执行聚合操作,应用非常广泛. 本章与 你真的会玩SQL吗?数据聚合 内容比较重要,还涉及到 你真的会玩SQL吗?Case ...

  8. ArcGis API FOR Silverlight 做了个导航工具~

    原文 http://www.cnblogs.com/thinkaspx/archive/2012/08/08/2628214.html 转载请注明文章出处:http://www.cnblogs.com ...

  9. 报LinkageError的原因

    LinkageError是一个比较棘手的异常,准确的说它是一个Error而不是Exception.java api对它没有直接的解释,而是介绍了它的子类: Subclasses of LinkageE ...

  10. java List与数组互转

    数组转List:String[] arr = new String[] {"str1", "str2"};List<String> list = A ...