以前自己用django开发网站,都是用的函数view,最近在学习Class View。
ListView 用于获取某个 model 的列表,获取的是一系列对象。
DetailView用于获取某个 model 的单个对象中,比如 Blog 里点击某篇文章后进入文章的详情页。
一、最简单的Class View
其实最简单位的view是这样的
class PublisherList(ListView): model = Publisher
url的设置是这样的:
urlpatterns = [ url(r'^publishers/$', PublisherList.as_view()), ]
如果你没有指定模板,则django会自动寻找books/publisher_list.html这个模板。
二、context_object_name有什么用?
如果你不使用context_object_name,你模板中的写法是这样的:
<ul> {% for publisher in object_list %} <li>{{ publisher.name }}</li> {% endfor %} </ul>
如果你使用context_object_name,你模板中的写法是这样的:
<ul> {% for publisher in publisher_list %} <li>{{ publisher.name }}</li> {% endfor %} </ul>
也就是说:
Using function based view:
def index(request): product_list = Product.objects.all() return render(request, 'product/index.html', {'product_list': **product_list**})
Using class based view
class ProductListView(ListView): model = Product template_name = 'product/index.html' context_object_name = 'product_list'
三、get_context_data 呈现额外信息
给传递到模板文件的上下文对象(context)添加额外的内容的,例如,你想在每个Publisher(出版商)详细信息页面上显示所有书籍的列表。
from django.views.generic import DetailView from books.models import Publisher, Book class PublisherDetail(DetailView): model = Publisher def get_context_data(self, **kwargs): # Call the base implementation first to get a context context = super(PublisherDetail, self).get_context_data(**kwargs) # Add in a QuerySet of all the books context['book_list'] = Book.objects.all() return context
还看到有人这样写的:
class IndexView(ListView): template_name = "blog/index.html" context_object_name = "article_list" model = Article def get_context_data(self, **kwargs): kwargs['category_list'] = Category.objects.all().order_by('name') return super(IndexView, self).get_context_data(**kwargs)
参考:https://blog.csdn.net/ros_donggua/article/details/81024650
四、自定义显示queryset
class BookList(ListView): queryset = Book.objects.order_by('-publication_date') context_object_name = 'book_list' class AcmeBookList(ListView): context_object_name = 'book_list' queryset = Book.objects.filter(publisher__name='ACME Publishing') template_name = 'books/acme_list.html'
五、动态过滤 get_queryset
但是如果我们想编写一个视图来显示某个任意出版商的所有书籍怎么办?
# urls.py from django.conf.urls import url from books.views import PublisherBookList urlpatterns = [ url(r'^books/([\w-]+)/$', PublisherBookList.as_view()), ]
class PublisherBookList(ListView): template_name = 'books/books_by_publisher.html' def get_queryset(self): self.publisher = get_object_or_404(Publisher, name=self.args[0]) return Book.objects.filter(publisher=self.publisher)
参考:https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/#making-friendly-template-contexts
例2:
通过get_queryset实现只显示已发表的文章。
六、执行额外的工作get_object
如果需要在获取过程中对获取的对象做一些处理,比如对文章做 markdown 拓展,通过复写 get_object 即可实现。
比如我们的 Author 模型中有一个 last_accessed 字段,我们用它来跟踪任何人最后一次查看该作者的时间。
# models.py from django.db import models class Author(models.Model): salutation = models.CharField(max_length=10) name = models.CharField(max_length=200) email = models.EmailField() headshot = models.ImageField(upload_to='author_headshots') last_accessed = models.DateTimeField()
from django.conf.urls import url from books.views import AuthorDetailView urlpatterns = [ #... url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetailView.as_view(), name='author-detail'), ]
然后我们将编写我们的新视图——get_object 是检索对象的方法——所以我们只需覆盖它并包装调用:
from django.views.generic import DetailView from django.utils import timezone from books.models import Author 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 = timezone.now() object.save() # Return the object return object