Django 自学笔记兼学习教程第7章第3节——拓展CBVs(Class-based views)

点击查看教程总目录

一般而言,直接使用原生的Class-based views,能展现的样式和内容是固定的。

为了根据实际情况去定制View,我们需要继承django自带的View并修改。

在修改之前,我们需要先了解下CBVs。

1 CBV的HTTP方法

先上一个例子,如果要用视图方法来处理各种HTTP方法,代码大概会如下:

# views.py
def simple_function_based_view(request):
if request.method == 'GET':
... # code to process a GET request
elif request.method == 'POST':
... # code to process a POST request

而使用CBV来处理的话,代码如下:

# views.py
from django.views import View class SimpleClassBasedView(View):
def get(self, request):
... # code to process a GET request def post(self, request):
... # code to process a POST request

对于浏览器发起的请求中使用的特定HTTP方法(GET、POST等),判断处理的代码组织可以通过CBV中单独的方法来解决,而不是通过条件分支。

且HTTP方法与CBV中单独的方法通过小写的方式匹配。

  • 即GET请求,对应CBV中的get方法;
  • POST请求,对应CBV中的post方法;
  • 其他请求同理

2 Class-based views常用方法

get_context_data()

Returns context data for displaying the object.

The base implementation of this method requires that the self.object attribute be set by the view (even if None). Be sure to do this if you are using this mixin without one of the built-in views that does so.

It returns a dictionary with these contents:

object: The object that this view is displaying (self.object).

context_object_name: self.object will also be stored under the name returned by get_context_object_name(), which defaults to the lowercased version of the model name.

返回用于显示对象的context数据,返回包含以下内容的词典:

  • object:此视图显示的对象(self.object).
  • context_object_nameself.object还将存储在get_context_object_name()返回的名称下,该名称默认为模型名称的小写版本。

PS: 需要修改context数据,可重写此方法

例子如下(出处:adding-extra-context

class PublisherDetail(DetailView):

    model = Publisher

    def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context

3 实例

拓展CreateView

欲实现:学生注册时,学生选择年级后注册,自动根据年级按序生成年级子学号

具体来说,一个年级没有学生的话,那么新注册的学生学号就是000001

一个年级有学生的话,取出所有学生里面的最大学号,新注册的学生学号就是最大学号增加1。

首先为学生注册实现一个表单,这个在之前第六章第四节

中有专门做过,这里直接把代码结果拿来用,关于代码的具体意思有不懂的,可以回去看一看

此时my_app/forms.py

from django import forms
from .models import Student class StuRegisterForm(forms.ModelForm):
confirm_password = forms.CharField(widget=forms.PasswordInput(), label="确认密码") class Meta:
model = Student
fields = ('grade',
'name',
'password',
'confirm_password',
'gender',
'birthday',
'email',
'info') def clean(self):
cleaned_data = super(StuRegisterForm, self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if confirm_password != password:
self.add_error('confirm_password', 'Password does not match.') return cleaned_data

my_app/views/register.py

from django.shortcuts import render
from django.http.response import HttpResponse,HttpResponseRedirect
from .models import Student
from django.views.generic import CreateView
from .forms import RegisterForm class CreateStudentView(CreateView):
model = Student
form_class = RegisterForm
# fields = "__all__"
template_name = "register.html"
success_url = "login" def form_valid(self, form):
# 学生注册时选定年级自动生成学号
grade = form.cleaned_data["grade"]
# order_by默认升序排列,number前的负号表示降序排列
student_set = Student.objects.filter(grade=grade).order_by("-number")
if student_set.count() > 0:
last_student = student_set[0]
new_number = str(int(last_student.number) + 1)
for i in range(6 - len(new_number)):
new_number = "0" + new_number
else:
new_number = "000001" # Create, but don't save the new student instance.
new_student = form.save(commit=False)
# Modify the student
new_student.number = new_number
# Save the new instance.
new_student.save()
# Now, save the many-to-many data for the form.
form.save_m2m() self.object = new_student
return HttpResponseRedirect(self.get_success_url())

对应urls.py里面的urlpatterns变量,添加对应的urlpattern如下

from django.urls import path

from my_app.views import login, register
from my_app import view urlpatterns = [
path('login/', login.page, name="login"),
path('hello/', view.hello), path('register', register.CreateStudentView.as_view(),
name="register"),
]

其中,用到的关联代码还有:

以上代码,只介绍下本节相关的内容,其他的

主要说下CreateStudentView

这个类首先继承了CreateView类,

然后重写了了专门的form_valid方法,根据自定义的需求,重新实现通过form表单内容生成model实例并保存的过程,并返回了自定义的重定向对象。

可能有人这里会对该方法感到疑惑,这里我们需要去看一下一些方法的源码,便于进一步的理解。

(以下算是进阶内容,是通过不断深入其代码源码分析出来的,不太看得懂的话推荐略过,暂时理解为可以在form_valid方法中重新定义“通过form表单内容生成model实例并保存”的逻辑。)

这个方法是用来处理提交表单的请求的,即POST请求,那么我们看下CreateViewpost方法,其post方法是继承BaseCreateViewpost方法:

    def post(self, request, *args, **kwargs):
self.object = None
return super().post(request, *args, **kwargs)

其中返回值中又调用了父类的post方法,即ProcessFormViewpost方法:

    def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)

阅读这个代码,我们可以判断出,其表单生成模型保存的过程应该只会是在return self.form_valid(form)这一句中,前面两句一句是获取表单内容,一句是验证表单。

然后我们再去看它的form_valid方法,CreateView的form_valid方法是继承ModelFormMixinform_valid方法

    def form_valid(self, form):
"""If the form is valid, save the associated model."""
self.object = form.save()
return super().form_valid(form)

这个方法中先进行了form表单数据的保存(即生成模型实例保存到数据库中)并赋值给self.object

然后又调用了父类的form_valid方法,即FormMixinform_valid方法

    def form_valid(self, form):
"""If the form is valid, redirect to the supplied URL."""
return HttpResponseRedirect(self.get_success_url())

该方法实现了返回重定向对象的功能,

所以我们要去实现的form_valid要实现上面两个工作

  • ModelFormMixinform_valid方法中的:form表单数据的保存(即生成模型实例保存到数据库中)并赋值给self.object
  • FormMixinform_valid方法中的:返回重定向对象的功能

最新文章

  1. trigger中insert动作的测试
  2. 线性SVM
  3. 使用eclipse+fiddler+微信web开发者工具调试本地微信页面
  4. Leetcode: Longest Substring with At Most K Distinct Characters && Summary: Window做法两种思路总结
  5. php fastcgi_finish_request让你的程序由等待时间,瞬间完成,提高用户体验
  6. 操作系统开发系列—12.g.在内核中设置键盘中断
  7. Scala之OOP
  8. svg学习(二)
  9. SpringMVC -- 梗概--壹
  10. [py]chr ord
  11. C++:获取数组长度
  12. [iOS基础控件 - 6.9.3] QQ好友列表Demo TableView
  13. PyTorch教程之Autograd
  14. MySQL5.6的optimizer_trace
  15. 流式处理的新贵 Kafka Stream - Kafka设计解析(七)
  16. Java中判断是否为空的方法
  17. Python函数绘图
  18. 使用Flask-CKEditor集成富文本编辑框
  19. outlook还原初始设置
  20. highCharts参数实例解释

热门文章

  1. C语言数组的创建和使用
  2. 一个故事,一段代码告诉你如何使用不同语言(Golang&C#)提供相同的能力基于Consul做服务注册与发现
  3. 从零入门 Serverless | 使用 Spot 低成本运行 Job 任务
  4. 如何在 Serverless K8s 集群中低成本运行 Spark 数据计算?
  5. 创建线程的4种方法 and 线程的生命周期
  6. Nginx安装及核心配置解析
  7. 解决pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.
  8. 【UE4 C++ 基础知识】<7> 容器——TSet
  9. Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)
  10. Linux C 数据结构 ->单向链表