Django框架:内置组件
一、django内置序列化组件
1.前夕
前后端分离的情况下,两者交互只能通过json格式的数据,后端视图函数返回的数据应该是一个Json格式的大字典,那我们只能自己封装成大字典
from app01 import models from django.http import JsonResponse def ser_func(request): # 1。查询所有的书籍对象 book_queryset = models.Book.objects.all() # 结果为QuerySet对象 [数据对象1,数据对象2] # 2。封装成大字典返回 data_dict = {} for book_obj in book_queryset: temp_dict = {} temp_dict['pk'] = book_obj.pk temp_dict['title'] = book_obj.title temp_dict['price'] = book_obj.price temp_dict['info'] = book_obj.info data_dict[book_obj.pk] = temp_dict # {"1":{},"2":{}...} return JsonResponse(data_dict)
2.序列化组件
django自带的serializers.serialize()
方法
# 导入内置序列化模块 from django.core import serializers def ser_func(request): # 1。查询所有的书籍对象 book_queryset = models.Book.objects.all() # 结果为QuerySet对象 [数据对象1,数据对象2] # serializers.serialize()方法第一个参数,是序列化数据的格式 res = serializers.serialize('json', book_queryset) return HttpResponse(res)
二、批量操作数据
1.循环插入
直接循环插入,10s 500条左右,效率很低
def bulk_data_func(request): for i in range(1, 10000): models.Book.objects.create(title="第%s本书" % i) book_queryset = models.Book.objects.all() return render(request, 'bulkPage.html', locals())
2.orm提供的操作
# orm提供的批量查询 def bulk_data_func(request): # 1.列表生成式生成对象,然后插入数据 book_obj_list = [models.Book(title="第%i本书" % i) for i in range(1, 10000)] # 通过类名加()生成对象 # 2 通过orm提供的批量操作插入 models.Book.objects.bulk_create(book_obj_list) # 3.查询所有表中数据展示到前端 book_queryset = models.Book.objects.all() return render(request, 'bulkPage.html', locals())
三、分页器
1.分页器思路
推导流程 1.queryset支持切片操作(正数) 2.研究各个参数之间的数学关系 每页固定展示多少条数据、起始位置、终止位置 3.自定义页码参数 current_page = request.GET.get('page') 4.前端展示分页器样式 5.总页码数问题 divmod方法 6.前端页面页码个数渲染问题 后端产生 前端渲染
- 分页器后端
# 分页器 def bulk_data_func(request): # 1.查询出所有表中的数据,并展示到前端 # 3.获取书籍总数量 book_all = models.Book.objects.all() book_count = book_all.count() per_page_num = 10 # 没页展示多少数据 # 4.开始分页 all_page_num, extra_num = divmod(book_count, per_page_num) if extra_num: all_page_num += 1 current_page = request.GET.get('page', 1) # 获取'page'键对应的值,如果没有则默认为1 # 2.前端拿到的是字符串,所以需要转换成整型,并且需要异常捕获防止一样 try: current_page = int(current_page) except BaseException: current_page = 1 start_num = (current_page - 1) * per_page_num end_num = current_page * per_page_num book_queryset = book_all[start_num:end_num] # 5 在模版上通过添加标签,并通过过滤器取消转义添加分页页码 html_str = '' real_page = current_page if real_page<6: real_page=6 for i in range(real_page - 5, real_page + 6): if current_page==i: html_str += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i) else: html_str += '<li><a href="?page=%s">%s</a></li>' % (i, i) return render(request, 'bulkPage.html', locals())
- 前端
{% for book_obj in book_queryset %} <p class="text-center">{{ book_obj.title }}</p> {% endfor %} {{ html_str|safe }}
2.自定义分页器使用
- 新建utils文件夹的自定义py文件内
class Pagination(object): def __init__(self, current_page, all_count, per_page_num=10, pager_count=11): """ 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :param pager_count: 最多显示的页码个数 """ try: current_page = int(current_page) except Exception as e: current_page = 1 if current_page < 1: current_page = 1 self.current_page = current_page self.all_count = all_count self.per_page_num = per_page_num # 总页码 all_pager, tmp = divmod(all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count self.pager_count_half = int((pager_count - 1) / 2) @property def start(self): return (self.current_page - 1) * self.per_page_num @property def end(self): return self.current_page * self.per_page_num def page_html(self): # 如果总页码 < 11个: if self.all_pager <= self.pager_count: pager_start = 1 pager_end = self.all_pager + 1 # 总页码 > 11 else: # 当前页如果<=页面上最多显示11/2个页码 if self.current_page <= self.pager_count_half: pager_start = 1 pager_end = self.pager_count + 1 # 当前页大于5 else: # 页码翻到最后 if (self.current_page + self.pager_count_half) > self.all_pager: pager_end = self.all_pager + 1 pager_start = self.all_pager - self.pager_count + 1 else: pager_start = self.current_page - self.pager_count_half pager_end = self.current_page + self.pager_count_half + 1 page_html_list = [] # 添加前面的nav和ul标签 page_html_list.append(''' <nav aria-label='Page navigation>' <ul class='pagination'> ''') first_page = '<li><a href="?page=%s">首页</a></li>' % (1) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): if i == self.current_page: temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,) else: temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一页</a></li>' else: next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,) page_html_list.append(next_page) last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,) page_html_list.append(last_page) # 尾部添加标签 page_html_list.append(''' </nav> </ul> ''') return ''.join(page_html_list)
- view.py中
def ab_pg_func(request): book_queryset = models.Books01.objects.all() from app01.utils.mypage import Pagination current_page = request.GET.get('page') page_obj = Pagination(current_page=current_page, all_count=book_queryset.count()) page_queryset = book_queryset[page_obj.start:page_obj.end] return render(request, 'pgPage.html', locals()) {% for book_obj in page_queryset %} <p>{{ book_obj.title }}</p> {% endfor %} {{ page_obj.page_html|safe }}
四、form组件
1.功能
- 自动校验数据
- 自动生成标签
- 自动展示信息
2.自动校验数据
(1)forms模块的关键字
- is_valid 是否合法,只要有一个不符合结果都是false
- cleaned_data 获取符合校验条件的数据
- errors 获取不符合校验规则的数据
1.默认所有的字段必须传值
2.定义字段之外,多传的数据会直接忽略不影响校验
(2)例
- views.py
class MyForm(forms.Form): # 代表username字段最少三个字符最大八个字符 username = forms.CharField(min_length=3, max_length=8) # age字段最小为0 最大为200 age = forms.IntegerField(min_value=0, max_value=200) # email字段必须符合邮箱格式 email = forms.EmailField()
-
测试
1.校验第一步,把一个字典传给创建的form类,实例化一个对象
2.通过对象点
is_valid()
方法,开始判断数据是否全部符合要求
# 测试views中的form组件 from app01 import views form_obj = views.MyForm({'username':'jason','age':18,'email':'123'}) # 1.判断数据是否全部符合要求,只有通过调用is_valid()才会开始校验 res = form_obj.is_valid() print(res) # False # 2.获取全部符合校验条件的数据 res1 = form_obj.cleaned_data print(res1) # {'username': 'jason', 'age': 18} # 3.获取不符合校验规则的数据及其原因 res2 = form_obj.errors print(res2) # <ul class="errorlist"><li>email<ul class="errorlist"><li>Enter a valid email address.</li></ul></li></ul>
当我们使用forms组件后,可以发现forms组件的功能
• 前端页面是form类的对象生成的 -->生成HTML标签功能
• 当用户名和密码输入为空或输错之后 页面都会提示 -->用户提交校验功能
• 当用户输错之后 再次输入 上次的内容还保留在input框 -->保留上次输入内容
3.form组件渲染标签
(1)渲染方式一:
完全全自动,封装程度过高,扩展性差,主要用于本地测试
{{ form_obj.as_p}} {{ form_obj.as_ul}} {{ form_obj.as_table}}
在字段中加label参数可修改label框的文本
(2)渲染方式2:
封装程度过低,扩展性高,但是编写繁琐
# label标签 {{ form_obj.username.label }} # input框 {{ form_obj.username }}
(3)渲染方式3:
封装程度较高,扩展性较高,编写简单推荐使用
# label标签 中文的注释,这个框渲染什么的 {{ form.label }} # 字段 input框 {{ form }}
注意方式:
1.forms组件只渲染用来获取用户数据的标签,除此之外的其他标签得自己编写,form标签、表单标签、提交按钮都需要自己编写
2.当我们在前端页面输入的时候,form组件会通过前端来自动帮我进行校验功能。
然而,前端的校验是弱不经风的,并且前端的校验可以在前端改掉。最终都需要后端来校验,所以需要我们在使用forms组件的时候,添加novalidate
属性把校验提示取消掉
<form action="" novalidate>

4.forms组件展示信息
后端不同请求返回的forms对象一定要是相同的变量名
(1)展示信息
-
后端
1.get请求和post传给html页面对象变量名(
form_obj
需要保持一致2.forms组件当你的数据不合法的情况下,会保存你上次的数据,让你基于之前的结果进行修改,更加的智能
from django import forms class MyForm(forms.Form): username = forms.CharField(min_length=3, max_length=8, label='用户名') age = forms.IntegerField(min_value=0, max_value=200) email = forms.EmailField() def form_func(request): # 1.产生一个空对象 form_obj = MyForm() if request.method == "POST": form_obj = MyForm(request.POST) # request.POST可以看成一个大字典,直接传给forms类校验,字典中无论有多少键值对,都只会验证类中编写的 if form_obj.is_valid(): # 启动校验,并判断校验是否合格 print(form_obj.cleaned_data) else: print(form_obj.errors) # 2.将该对象传递给html页面,当get请求时传递的是空对象,当post请求时传递的是request.POST大字典,但是由于用的都是统一个模版,所以需要两者同名 return render(request, 'formPage.html', locals())
-
前端通过模版语法
注意,forms组件只会帮我们填写input标签,其他的标签都要自己编写
<form action="" method="post"> {% for form in form_obj %} <p> {{ form.label }} {{ form }} <span>{{ form.errors }}</span> </p> {% endfor %} <input type="submit"> </form>
(2)错误信息修改成中文
错误消息默认都是英文,并且内容是固定的,我们可以通过以下两种方法来修改成中文
- 方式1:自定义中文错误消息内容
给字段对象添加errors_messages
参数

- 前端展示效果
-
方式2:修改系统语言环境
误信息的提示,可以修改成各国语言
语言配置
简体中文与繁体中文

5.forms组件校验补充
form组件对于字段数据的校验,提供了三种类型的校验方式,这三种方式可以一起使用
(1)第一种类型:直接填写参数
max_length
(2)第二种类型:使用正则表达式
# validators + 正则校验器 class MyForm(Form): user = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], )

(3)第三种校验:钩子函数(HOOK)
1.作用:,在特定的节点自动触发完成响应操作
2.什么是钩子函数?
编写代码能自定义校验方式
3.触发条件:在字段都已经校验所有的参数之后,基于is_valid之后,cleaned_data之后
校验顺序:1.max_length 2.正则 3.钩子函数
4.局部钩子:每次只校验一个字段:校验用户名是否存在
def clean_username(self): username = self.cleaned_data.get('username') if username == 'duoduo': self.add_error('username', '用户名duoduo已存在') return username
5.全局钩子:一次校验多个字段数据:校验两次密码是否一致
def clean(self): password = self.cleaned_data.get('password') confirm_pwd = self.cleaned_data.get('confirm_pwd') if not password == confirm_pwd: self.add_error('confirm_pwd', '两次密码不一致') return self.cleaned_data
6.forms组件参数补充
(1)常见参数
- min_length 最小字符
- max_length 最大字符
- min_value 最小值
- max_value 最大值
- label 字段注释
- error_message 错误提示
- validators 正则校验器
- initial 给字段添加默认值
- required=False 可以不填数据
(2)字段属性和字段样式
- widget 控制标签的各种属性
7.forms组件源码
8.modelform组件
forms组件的强化版本,更好用
forms组件针对前端用户模型表的录入前校验
from django import forms from app01 import models class MyModelForm(forms.ModelForm): class Meta: model = models.UserInfo fields = '__all__' labels = { 'username':'用户名' } def ab_mf_func(request): modelform_obj = MyModelForm() if request.method == 'POST': modelform_obj = MyModelForm(request.POST,instance=User_obj) if modelform_obj.is_valid(): modelform_obj.save() # models.UserInfo.objects.create(...)/update(...) else: print(modelform_obj.errors) return render(request, 'modelFormPage.html', locals())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY