表单自定义校验
之前的学习过程当中讲解了form表单的定义,首先,我们来回顾一下form表单的定义和使用的流程
以文章的评论为案例。
1、定义form.py文件,在form文件当中定义表单校验类
2、在视图当中调用form表单类
3、前端渲染表单类
总的看起来,学习的过程当中要注意以下几点
- 表单定义
\OurBlog\Article\forms.py
#coding:utf-8
from django import forms
from ckeditor_uploader.fields import RichTextUploadingFormField
class CommentForm(forms.Form):
"""
自定义form表单,完成评论表单
"""
content = RichTextUploadingFormField(label = "评论内容") #创建一个文本标签元素
from Article.models import Comment
class CommentForm_about_model(forms.ModelForm):
"""
按照数据库模型进行表单的定义
"""
class Meta:
model = Comment #创建表单对应的数据模型的类
fields = ["content"] #要创建的字段
labels = {
"content": "评论内容" #设置content字段的label标签
}
# fields 要展示的字段,接收的是一个列表,如果不写默认是models的所有字段(__all__)
# exclude 不要展示的字段,接收的是一个列表,排除的字段,默认没有
# widgets 是一个模型字段的名称对应的样式的字典
# labels 是一个模型字段的名称对应的标签的字典
# help_texts 是一个模型字段的名称对应的帮助文档的字典
# error_messages是一个模型字段的名称对应的错误提示的字典,这个将在后面学习开发CMDB的时候用户注册用的比较频繁
- 在视图当中调用form表单类
在视图文件导入表单类,并且实例化
\OurBlog\Article\views.py
from Article.forms import CommentForm_about_model
def Article(request):
form = CommentForm_about_model()
return render(request, "article/aboutMe.html",{"form":form})
在前端调用和渲染,注意,我们用的是ckeditor插件,所以需要插件的样式,我们需要在{% block style %}模块进行导入我们的js文件
<!--......-->
{% block style %}
<link href="/static/article/css/main.css" rel="stylesheet">
<script src = "/static/article/js/jquery.js"></script>
<script src = "/static/ckeditor/ckeditor-init.js"></script>
<script src = "/static/ckeditor/ckeditor/ckeditor.js"></script>
{% endblock %}
<!--......-->
<div>
{{ form }}
</div>
<!--......-->
效果如下:
上述的功能足够90%的需求使用,但是评论的内容限制,(不允许提交html代码等),这些完全符合当前业务需求的点是不好设置的,那么就需要学习如何自定义校验了。
自定义校验是在form表单里面通过"clean_字段名称"开头的类来进行的
在form表单当中,我们进行数据校验需要三步:
1、 将我们收到的数据传入表单
2、 进行校验 is_valid
3、 获取校验之后的数据 clean_data
首先views进行表单数据校验
from Article.forms import CommentForm_about_model
def Article(request):
form = CommentForm_about_model()
if request.method == "POST" and request.POST:
data = CommentForm_about_model(request.POST)
if data.is_valid(): #校验数据
#……
然后进行自定义校验
def clean_content(self):
"""
form表单自定义校验的函数名称必须是clean_加上字段名称
校验content,函数名称就叫做clean_content
"""
data = self.cleaned_data.get("content") #获取提交的值
if "while" in data: #判断条件
raise forms.ValidationError("don't speek while") #这个错误类型是form表单类定义好的,这里引发的错误,会放到errors当中
else:
return data #如果正常,我们需要返回数据
那么大家可以想一想我们是否可以重写或者重写调用Django父类当中的方法?
Django数据库模型对象 queryset
queryset是查询集,就是传到服务器上的url里面的内容。
Objects就是Django定义好的一个queryset,queryset定义在manager方法当中
Objects常用的方法
All
Filter
Order_by
Limit
Add
Create
Update
delete
对于queryset对象,需要掌握以下几点:
- Django会对查询返回的结果集QuerySet进行缓存,这里是为了提高查询效率。也就是说,在你创建一个QuerySet对象的时候,Django并不会立即向数据库发出查询命令,只有在你需要用到这个QuerySet的时候才会去数据库查询。
- Objects是django实现的mvc框架中的数据层(model)m,django中的模型类都有一个objects对象,它是一个django中定义的QuerySet类型的对象,它包含了模型对象的实例。简单的说,objects是单个对象,queryset是多个对象。
- QuerySet 可以被构造,过滤,切片,做为参数传递,这些行为都不会对数据库进行操作。只有查询的时候才真正的操作数据库。
1、循环(Iteration):QuerySet 是可迭代的,在你遍历对象时就会执行数据库操作。
2、切片(Slicing): QuerySet 是可以用 Python 的数组切片语法完成切片。一般来说对一个未查询的 QuerySet 切片就返回另一个未查询的 QuerySet (新 QuerySet 不会被执行)。
切片的step操作会导致结果集进行数据库查询, 也就是我们常说的步长
Article.objects.all()[1:10] 不查询
Article.objects.all()[1:10:2] 查询
3、repr(). 调用 QuerySet 的 repr() 方法时,查询就会被运行。
4、 len() .调用 QuerySet 的 len() 方法,查询就会被运行
Django 还提供了 count() 方法,他使用了 SQL 的 SELECT COUNT(*) 机制
Django自定义queryset
在上面的案例当中,我们研究QuerySet,但实际工作当中,我们需求的查询和orm查询往往有差距,所以我们需要自定义
- 表级的自定义查询
\OurBlog\Article\models.py
class ArticleManager(models.Manager):
"""
返回文章的总数
定义一个查询集
"""
def article_conunt(self,keyword = ""): #查询集的名称
return self.filter(title__icontains = keyword).count() #__icontains进行数据模糊查询 类似like
class Article(models.Model):
"""
一篇文章可以有一个作者,一个作者可以有一篇文章,
一篇文章有多条评论
一个文章有多个分类
一个分类有多篇文章
"""
#...... 这里省略了已经写好的代码
#安装查询集
objects = ArticleManager() #安装查询集
def __str__(self):
return "文章:%s" % self.title
视图调用
\OurBlog\Article\views.py
def example(request):
all_data = Article.objects.all()
count = Article.objects.article_count("while没有写例子") #调用自定义的查询方法
return render(request,"article/example_model.html",locals())
前端调用
\OurBlog\Article\templates\article\example_model.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Model Example</title>
</head>
<body>
{% for article in all_data %}
<p>
{{ article.title }}
</p>
{% endfor %}
<p>
{{ count }}
</p>
</body>
</html>
- 行级的自定义查询
定义自定义查询类:
class Article(models.Model):
"""
一篇文章可以有一个作者,一个作者可以以有一篇文章,
一篇文章有多条评论
一个文章有多个分类
一个分类有多篇文章
"""
title = models.CharField(max_length = 32,verbose_name = "文章标题")
time = models.DateField(verbose_name = "文章发表日期")
description = RichTextUploadingField(verbose_name = "文章描述")
content = RichTextUploadingField(verbose_name = "文章内容")
picture = models.ImageField(verbose_name = "文章图片",upload_to = "images/article")
author = models.ForeignKey(Author)
classify = models.ManyToManyField(Classify)
commant = models.ForeignKey(to=Comment, verbose_name="文章评论", blank = True,null = True) #文章可以有评论,也可以没有,""代表blank,None代表null
def valid_title(self):
"""
定义查询集
"""
title = self.title #获取title字段的内容
if "while" in title: #进行判断返回指定结果
return "这个文章牛"
else:
return "一般般吧"
前端调用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Model Example</title>
</head>
<body>
{% for article in all_data %}
<p>
{{ article.title }} <!--这里显示文章的title-->
{{ article.valid_title }} <!--这里显示我们自定义查询集返回的结果-->
</p>
{% endfor %}
<p>
<!--这里返回查询文章的总数-->
{{ count }}
</p>
</body>
</html>
效果如下:
如果你的文章中是不同的title,查询出来的结果是不一样的,就不像我这个这么统一了,我这个是为了偷懒,全是复制粘贴添加的一样的数据,快去试试自己的Blog