django框架-7
2022/9/8 23:53:09
本文主要是介绍django框架-7,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- Ajax
- 序列化
- 批量操作数据
- 批量数据展示
- 自定义分页器
- form组件
- form组件源码分析
- modeform组件
Ajax
异步提交 局部刷新 与form表单的区别可以参考 码云 网址的注册页手机号输入框 Ajax其实是js自带的功能 不是一门新的技术点 我们学习的是jQuery封装之后版本 1.基础语法 $.ajax({ url:'', 控制数据的提交地址 默认是朝本页面发送 type:'', 控制请求方式(默认是get请求) data:{}, 组织提交的数据 success:function(形参){ 异步回调函数 } }) 2.数据编码格式 Content-Type 格式1:urlencoded 数据格式:name=curry&pwd=666&hobby=read django后端统一处理到request.POST中 格式2:formdata 数据格式:无法查阅 django后端自动将文件数据处理到request.FILES 普通数据request.POST 格式3:application/json 数据格式:json格式 django后端不会处理 在request.body中存储(bytes类型) 自己处理 语法注意事项 data:JSO.stringify({'name':'curry','pwd':666}), contentType:'application/curry', 3.ajax携带文件数据 $('#d3').click(function (){ 1.产生内置对象 let formData = new FormData(); 2.添加普通数据 formData.append('username',$('#d1').va1()) 3.添加文件数据 fromData.append('file',$('#d2')[0].files[0]) 4.发送Ajax请求 $.ajax({ url:'', type:'post', data:formData, contentType:false, 不使用任何编码 processDate:false, 不处理数据对象 success:function(args) { } }) }) 4.回调函数 后端跟Ajax交互 不应该再返回页面 通常情况下都是返回json格式数据 前端针对HttpResponse和JsonResponse返回的json格式数据处理策略不同 前者不会自动反序列化 而后者会自动反序列化 如果想让前者也自动反序列化可以添加一个固定的参数 dataType:'JSON'
序列化
def ser(request): # 拿到用户表里面的所有的用户对象 user_list=models.User.objects.all() # 导入内置序列化模块 from django.core import serializers # 调用该模块下的方法,第一个参数是你想一什么样的方式序列化你的数据 ret = serializers.serialize('json',user_list) return HttpResponse(ret)
批量操作数据
浏览器访问一个django路由 立刻创建10万条数据并展示到前端页面 关键词:create(创建)、all(全部) 涉及到大批量数据的创建 直接使用create可能会造成数据库崩溃 批量数据创建>>>:bulk_create() 批量数据修改>>>:bulk_update() def index(request): for i in range(10000): book_obj = models.Book(title=f'第{i}本书') book_list,append(book_obj) '''上述四行可以简写为一行>>>:列表生成式(列表表达式)''' models.Book.objects.bulk_create(book_list) # 批量创建数据 book_query = models.Book.objects.all() return render(request,'bookList.html',locals)
批量数据展示
当数据量比较大的时候 页面展示应该考虑分页 1.QuerySet切片操作 2.分页样式添加 3.页码展示 如何根据总数据和每页展示的数据得出总页码 divmod() 4.如何渲染出所有的页码标签 前端模板语法不支持range 但是后端支持 所以我们用到之前的思路咱不用 可以在后段创建好html标签然后传递给html页面使用 5.如何限制住展示的页面标签个数 页码推荐使用奇数位(因为对称) 利用当前页前后固定位数来限制 6.首尾页码展示范围问题 """ 上述是分页器组件的推导流程 我们无需真正编写 django自带一个分页器组件 但是不太好用 自己写一个 直接用就行 """
自定义分页器
自定义封装页码: class Pagination(object): def __init__(self, current_page, all_count, per_page_num=2, 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) 前端: {% for book_obj in page_query %} <p class="text-center">{{ book_obj.title }}</p> {% endfor %} {{ page_obj.page_html|safe }} 后端: from app01.plugins import mypage book_query = models.Book.objects.all() page_obj = mypage.Pagination(current_page=request.GET.get('page'), all_count=book_query.count() ) page_query = book_query[page_obj.start:page_obj.end] return render(request, 'bookList.html', locals())
form组件
form组件的主要功能如下: 1.生成页面可用的HTML标签 2.对用户提交的数据进行校验 3.保留上次输入内容 前戏:编写用户登录功能并且校验数据返回提示信息(form表单) def ab_form(request): data_dict = {'username':'','password':''} if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'curry': data_dict['username'] = '不让用curry' if password == '666': data_dict['password'] = '非要666???' return render(request,'ab_form.html',locals()) form类型创建 from django import forms class MyForm(forms.Form): name = forms.CharField(max_length=8, min_length=3) # 用户名最长八个字符 最短三个字符 age = forms.IntegerField(max_value=150, min_value=0) # 年龄最小0岁 最大150岁 email = forms.EmailField() # 邮箱必须符合邮箱格式(至少有个@符号) 1.数据校验功能 1.1.传递待校验的数据 form_obj = views.MyForm({'name':'jason','age':18,'email':123}) 1.2.判断所有的数据是否符合校验 form_obj.is_valid() 1.3.获取符合校验规则的数据 form_obj.cleaned_data {'name': 'jason', 'age': 18} 1.4.查阅不符合校验规则的数据及错误原因 form_obj.errors {'email': ['Enter a valid email address.']} """ 1.form类中编写的字段默认都是必填的 少传则肯定通不过校验 is_valid 2.校验如果多传了一些字段 则不参与校验 全程忽略 """ 2.渲染标签功能 2.1.方式1(封装程度高 扩展性差) {{ form_obj.as_p }} {{ form_obj.as_table }} {{ form_obj.as_ul }} 2.2.方式2(封装程度低 扩展性好 编写困难) {{ form_obj.name.lable }} {{ form_obj.name }} 2.3.方式3(推荐使用) {% for form in form_obj %} <p>{{ form.label }}{{ form }}</p> {% endfor %} """ 类中以外的所有标签都不会自动渲染 需要自己编写 """ 3.展示提示信息 form表单如何取消浏览器自动添加的数据校验功能 <form action="" method="post" novalidate> {% for form in form_obj %} <p> {{ form.label }}{{ form }} <span style="color: red;">{{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit" value="提交"> def func(request): form_obj = MyForm() if request.method == 'POST': form_obj = MyForm(request.POST) if form_obj.is_valid(): print(form_obj.cleaned_data) return render(request,'func.html',locals()) 重要的字段参数 max_length、min_length 最大小长度 max_value、min_value 最大小值 label 字段注释 error_messages 错误提示 required 是否为空 widget 标签类型、标签属性 initial 默认值 validators 正则校验 钩子函数 定义:提供自定义的校验方式 局部钩子:校验单个字段 def clean_name(self): name = self.cleaned_data.get('name') res = models.User.objects.filter(name=name).first() if res: return self.add_error('name','用户名已存在') return name 全局钩子:校验多个字段 def clean(self): pwd = self.cleaned_data.get('pwd') confirm_pwd = self.cleaned_data.get('confirm_pwd') if not pwd == confirm_pwd: return self.add_error('confirm_pwd','两次密码不一致') return self.cleaned_data
form组件源码分析
is_valid如何校验数据进行分析。 1.查看类源码发现只要给类传参self.is_bound肯定是True,重点看self.errors def is_valid(self): return self.is_bound and not self.errors 2.查看了源码发现self._errors初始化就是None 所以肯定看full_clean方法 @property def errors(self): if self._errors is None: self.full_clean() return self._errors 3.查看full_clean方法,发现主要有3个方法。 def full_clean(self): self.cleaned_data = {} # 创建了一个存储检查没问题的数据的空字典 self._clean_fields() # 校验数据 self._clean_form() # 封装 self._post_clean() # 返回 4.查看self._clean_fields方法 def _clean_fields(self): for name, field in self.fields.items():# 循环获取字段名和字段对象 if field.disabled: # 字段是否是禁用的 value = self.get_initial_for_field(field, name) else: value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) # 如果不是禁用,获取字段对应的用户数据,进行校验 try: # 异常捕获 if isinstance(field, FileField): # 文件数据 initial = self.get_initial_for_field(field, name) value = field.clean(value, initial) else: value = field.clean(value) # clean校验的方法 self.cleaned_data[name] = value # 以上校验没有问题,就上传到cleaned_data里 if hasattr(self, 'clean_%s' % name): # 利用反射判断是否拥有clean_%s的方法,就是在获取钩子函数执行, value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value # 钩子函数不报错,添加到cleaned_data里 except ValidationError as e: # 钩子函数报错,添加提示保存信息 self.add_error(name, e) 查看源码发现校验数据的整个过程内部都有异常处理机制 from django.core.exceptions import ValidationError raise ValidationError('用户名不存在') # 自己在clean_%s钩子函数主动抛出一个异常,也不会报错,因为钩子函数是交给_clean_fields这个方法里执行的,就算clean_%s报错也是交给了_clean_fields方法里的异常捕获处理。
modeform组件
modelform是form的优化版本 使用更简单 功能更强大 form与model的终极结合 # 后端 class MyModelFrom(forms.ModelForm): class Meta: model = models.User fields = '__all__' def clean_name(self): name = self.cleaned_data.get('name') res = models.User.objects.filter(name=name).first() if res: self.add_error('name', '用户名已存在') return name def ad(request): modelform_obj = MyModelFrom() if request.method == 'POST': modelform_obj = MyModelFrom(request.POST) if modelform_obj.is_valid(): modelform_obj.save() return render(request, 'ad.html', locals()) # 前端 <form action="" method="post" class="form-row"> {% for modelform in modelform_obj %} <p> {{ modelform.label }}{{ modelform }} </p> {% endfor %} <input type="submit" value="提交"> </form>
这篇关于django框架-7的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享
- 2024-12-10搭建个人博客网站之一、使用hugo创建个人博客网站