基于类的视图的介绍
Django之前一直用的视图函数,但是视图函数有一定的限制,不易扩展或者自定义。而基于类的视图就是为了解除视图函数的限制。它使用Mixin等基类使得开发更加便捷。
在基于类的视图中,我们不必像视图函数中那样,针对不同的请求方法,写分支语句。而是只需要重构实例方法即可。
视图函数中处理HTTP GET 的代码看上去将像:
from django.http import HttpResponse
def my_view(request):
if request.method == 'GET':# <view logic>
return HttpResponse('result')
在基于类的视图中,它将变成:
from django.http import HttpResponse
from django.views.generic import View
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
def post(self, request):
# <view logic>
return HttpResponse('result')
因为Django 的URL 解析器将请求和关联的参数发送给一个可调用的函数而不是一个类,所以基于类的视图有一个as_view() 类方法用来作为类的可调用入口。该as_view 入口点创建类的一个实例并调用dispatch() 方法。dispatch 查看请求是GET 还是POST 等等,并将请求转发给相应的方法,如果该方法没有定义则引发HttpResponseNotAllowed。
使用内建的通用类的视图,会自带一些变量,如user,csrftoken等等。
下面是我写的一个实例:
class ChangePwdView(View):
template_name = 'dashboard/changepasswd.html'
form_class = PasswordChangeForm
def get(self, request, *args, **kwargs):
form = PasswordChangeForm(request.user)
return render(request,self.template_name,{'form':form})
def post(self, request, *args, **kwargs):
form = PasswordChangeForm(request.user,request.POST)
if form.is_valid():
form.save()
auth.logout(request)
return HttpResponseRedirect('/account/login/')
return render(request,self.template_name,{'form':form})
@method_decorator(login_required(login_url='/account/login/'))
def dispatch(self, *args, **kwargs):
return super(ChangePwdView, self).dispatch(*args, **kwargs)
在开发中,经常使用基于类的内建通用视图,会进一步简化开发过程。 内建的显示(对象)视图主要有ListView,DetailView,TemplateView。
ListView是定义多个Django对象,返回一个查询集。通常要定义query_set,以及get_context_data(获取额外上下文).
DetailView是定义单个Django对象,返回单个查询结果,并显示其详细信息。
下面是我项目中的一个例子:
class BaseMixin(object):
def get_context_data(self,*args,**kwargs):
context = super(BaseMixin, self).get_context_data(**kwargs)
try:
context['website_name'] = u'千与千寻'
context['categories'] = Category.available_categories()
context['hottest_articles'] = Article.get_hottest_articles()
context['latest_articles'] = Article.get_latest_articles()
except Exception:
logger.error('load inital context fails')
return context
class IndexView(BaseMixin,ListView):
template_name = 'index.html'
paginate_by = NUM_PER_PAGE
context_object_name = 'article_list'
def get_queryset(self):
self.keyword = self.request.GET.get('keyword')
if not self.keyword:
self.article_list = Article.objects.filter(status=0)
else:
query_sql =( Q(title__icontains=self.keyword) | Q(content__icontains=self.keyword))
self.article_list = Article.objects.filter(query_sql,status=0)
return self.article_list
def get_context_data(self,*args,**kwargs):
context = super(IndexView,self).get_context_data(**kwargs)
length = len(self.article_list)
context['article_list_length'] = length
context['keyword'] = self.keyword
context['logion'] = get_logion()
number = length if length < 5 else 5
context['carousel_page_list'] = random.sample(self.article_list,number)
return context
get_queryset方法用来过滤查询集合,get_context_data用来获得额外的上下文。 BaseMinxin的用法在Django中比较常见,功能类似于utils里面的功用函数。
除了显示视图之外,还有编辑视图,FormView,CreateView,UpdateVIew,DeleteView等等。 当我们要提交表单的时候,可以使用FormView类。 我分别写了一个普通的用于处理表单的视图函数和一个FormView子类,对比看一下:
def Login(request):
errors = []
if request.method == 'POST':
form = UserLoginForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
username,password = cd['username'],cd['password']
if not username:
errors.append(u'请输入用户名')
if not password:
errors.append(u'请输入密码')
user = auth.authenticate(username=username,password=password)
if user is not None:
auth.login(request,user)
#this will rewrite html
return HttpResponseRedirect("/")
else:
errors.append(u'无效的用户名或密码,请重新登录。')
else:
pass
else:
form = UserLoginForm()
return render(request,'dashboard/login.html',{'form':form,'errors':errors})
class LoginFormView(FormView):
template_name = 'dashboard/viewlogin.html'
form_class = UserLoginForm
success_url = '/'
def form_valid(self, form):
cd = form.cleaned_data
username,password = cd['username'],cd['password']
if not username:
errors.append(u'请输入用户名')
if not password:
errors.append(u'请输入密码')
user = auth.authenticate(username=username,password=password)
if user is not None:
auth.login(self.request,user)
return super(LoginFormView,self).form_valid(form)
写的LoginFormView要比普通的视图函数简单得多,只需要重构一个form_valid即可。 它会自动获得Post数据后获得的表单。
关于编辑视图,我就拿一个官网例子说明一下吧。
from django.views.generic.edit import CreateView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from models import Book
from forms import BookForm
class AddBook(CreateView):
form_class = BookForm
model = Book
template_name = 'addbook.html' #这里是你的模板文件名
这个视图就可以实现Book的添加,如此来看真的很简单,只需要Book的Model模型,Book的表单,就可以实现。
微信分享/微信扫码阅读