• 13:基于类的通用视图


    基于类的通用视图

    前面我们说过了django的通用视图,不知道django通用视图的去看我前面的随笔,谢谢

    django的通用视图帮我们省略了很多代码,但有时候django的通用视图并不能满足我们全部的需求,例如像重定义一些属性和方法的时候,或者我们想换种写法的时候,因此,django提供了基于类的通用视图,通过子类或者在url中传参的方法来配置我们的基于类的通用视图

    通用视图和基于类的通用视图是两种不一样的写法,前面我们介绍的通用视图,所有的代码集中于url的配置文件中,而基于类的通用视图主要集中于配置“继承然后覆盖父类方法和属性”方面,下面是一个基于函数的视图和基于类的视图的对应关系

    基于函数基于类
    django.views.generic.simple.direct_to_template django.views.generic.base.TemplateView
    django.views.generic.simple.redirect_to django.views.generic.base.RedirectView
    django.views.generic.list_detail.object_list django.views.generic.list.ListView
    django.views.generic.list_detail.object_detail django.views.generic.detail.DetailView
    django.views.generic.create_update.create_object django.views.generic.edit.CreateView
    django.views.generic.create_update.update_object django.views.generic.edit.UpdateView
    django.views.generic.create_update.delete_object django.views.generic.edit.DeleteView
    django.views.generic.date_based.archive_index django.views.generic.dates.ArchiveIndexView
    django.views.generic.date_based.archive_year django.views.generic.dates.YearArchiveView
    django.views.generic.date_based.archive_month django.views.generic.dates.MonthArchiveView
    django.views.generic.date_based.archive_week django.views.generic.dates.WeekArchiveView
    django.views.generic.date_based.archive_day django.views.generic.dates.DayArchiveView
    django.views.generic.date_based.archive_today django.views.generic.dates.TodayArchiveView
    django.views.generic.date_based.object_detail django.views.generic.dates.DateDetailView

    简单用法

    考虑你仅仅想要显示一个模板about.html,django提供了一个通用视图去做这件事,我们只需要继承它,然后覆盖覆盖模板名称即可,其实TemplateView类对应的是direct_to_template

    # some_app/views.py
    from django.views.generic import TemplateView
    class AboutView(TemplateView):
        template_name = "about.html"

    然后再url配置文件中直接调用相应的方法即可

    # urls.py
    from django.conf.urls import patterns, url, include
    from some_app.views import AboutView
    urlpatterns = patterns('',
        (r'^about/', AboutView.as_view()),
    )

    或者我们可以直接在url中通过传参的方法达到修改属性的目的

    from django.conf.urls import patterns, url, include
    from django.views.generic import TemplateView
    urlpatterns = patterns('',
        (r'^about/', TemplateView.as_view(template_name="about.html")),
    )

    对象的通用视图

    首先这是我们可能会用到的model

    # models.py
    from django.db import models
    class Publisher(models.Model):
        name = models.CharField(max_length=30)
        address = models.CharField(max_length=50)
        city = models.CharField(max_length=60)
        state_province = models.CharField(max_length=30)
        country = models.CharField(max_length=50)
        website = models.URLField()
        class Meta:
            ordering = ["-name"]
        def __unicode__(self):
            return self.name
    class Book(models.Model):
        title = models.CharField(max_length=100)
        authors = models.ManyToManyField('Author')
        publisher = models.ForeignKey(Publisher)
        publication_date = models.DateField()

    为了生成一个所有出版商的页面,我们可以在url中这样写

    from django.conf.urls import patterns, url, include
    from django.views.generic import ListView
    from books.models import Publisher
    urlpatterns = patterns('',
        (r'^publishers/$', ListView.as_view(
            model=Publisher,
        )),
    )

    在这里我们没有指定模板名,那么会使用ListView默认的模板名默认模板<app_label>/<model_name>_list.html ,这里可能是/books/publisher_list.html

    拓展通用视图

    制作友好的模板上下文名称

    如果你在和模型打交道,使用下面的配置可以使你自己定义一个更好用(django内部有规则生成一个)的模板上下文名称,这可能使得和你合作的模板设计师对你有好感,因为有时候django自动生成的模板上下文名称很冗长

    urlpatterns = patterns('',
        (r'^publishers/$', ListView.as_view(
            model=Publisher,
            context_object_name="publisher_list",
        )),
    )

    增加额外的上下文内容

    有时候默认的通用视图提供的上下文内容不能满足你的需求,比如一个返回所有出版商的列表的页面,上面可能一点和书籍的信息都没有,这时候你可以通过继承相应的父类,覆盖父类的方法为子类添加额外的内容

    from django.views.generic import DetailView
    from books.models import Publisher, Book
    class PublisherDetailView(DetailView):
        context_object_name = "publisher"
        model = Publisher
        def get_context_data(self, **kwargs):
            # Call the base implementation first to get a context
            context = super(PublisherDetailView, self).get_context_data(**kwargs)
            # Add in a QuerySet of all the books
            context['book_list'] = Book.objects.all()
            return context

    对象的查看子集

    注意到的一点,model属性和queryset属性,model=Publisher和queryset=Publisher.objects.all()基本是一致的,基于这一点,我们可以通过制定queryset的方法以至于不必每次都收返回一个模型的全集,可以每次只返回一个子集,当然,我们也可以在url中达到这个目标

    urlpatterns = patterns('',
        (r'^publishers/$', ListView.as_view(
            queryset=Publisher.objects.all(),
            context_object_name="publisher_list",
        )),
        (r'^books/$', ListView.as_view(
            queryset=Book.objects.order_by("-publication_date"),
            context_object_name="book_list",
        )),
    )
    from django.views.generic import ListView
    from books.models import Book
    class AcmeBookListView(ListView):
        context_object_name = "book_list"
        queryset = Book.objects.filter(publisher__name="Acme Publishing")
        template_name = "books/acme_list.html"

    动态筛选

    还有一个常用的需求是根据url中的参数去查询数据库,之前我们可以把出版商的名字硬编码在url中,但如果我们要写一个能够根据任意给定的出版商,返回该出版商的所有书籍的视图呢?我们可以覆盖get_queryset()这个方法

        def get_queryset(self):
            publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
            return Book.objects.filter(publisher=publisher)

    执行额外的工作

    假如Author这个模型有一个last_accessed的date类型属性,我们要求每次访问的时候都更新这个属性,显然,django的通用视图是根本不知道Author有这样的一个属性的,所以我们必须重写某个方法以增加这个行为,在这里是get_object()方法

    import datetime
    from books.models import Author
    from django.views.generic import DetailView
    from django.shortcuts import get_object_or_404
    class AuthorDetailView(DetailView):
        queryset = Author.objects.all()
        def get_object(self):
            # Call the superclass
            object = super(AuthorDetailView, self).get_object()
            # Record the last accessed date
            object.last_accessed = datetime.datetime.now()
            object.save()
            # Return the object
            return object

    装饰基于类的视图

    在url中装饰

    from django.contrib.auth.decorators import login_required, permission_required
    from django.views.generic import TemplateView
    from .views import VoteView
    urlpatterns = patterns('',
        (r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
        (r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
    )

    在类中装饰

    from django.contrib.auth.decorators import login_required
    from django.utils.decorators import method_decorator
    from django.views.generic import TemplateView
    class ProtectedView(TemplateView):
        template_name = 'secret.html'
        @method_decorator(login_required)
        def dispatch(self, *args, **kwargs):
            return super(ProtectedView, self).dispatch(*args, **kwargs)

    p

  • 相关阅读:
    IOS回调机制总结
    2.25~当svn服务器ip地址变了怎么办?
    ubuntu硬件信息,内存DDR详细信息
    关于JS相等比较算法(==)的原理
    ubuntu更改鼠标滚轮方向为自然方向(运动方向和滚轮滚动方向一致)
    C#模拟js的Json对象创建,操作
    关于json返回日期格式化的解决方案
    js定时器 timer
    ubuntu GUI界面复制文件没权限的解决方案
    CodeSmith 模板
  • 原文地址:https://www.cnblogs.com/qwj-sysu/p/4199829.html
Copyright © 2020-2023  润新知