当使用django创建修改数据量特别大的数据时,用批量操作数据可以降低操作时间。 eg:浏览器访问一个django路由 立刻创建1万条数据并展示到前端页面 #涉及到大批量数据的创建,使用create()创建可能会造成数据库崩溃!且加载还慢!效率差! 批量数据创建>>>:bulk_create() 批量数据修改>>>:bulk_update() def index(request): book_list = [] for i in range(10000): book_obj = models.Book(title=f'第{i}本书') book_list.append(book_obj) ''' 上述四行可以简写为一行>>>:列表生成式(列表表达式): [models.Book(title=f'第{i}本书')for i in range(10000)] ''' models.Book.objects.bulk_create(book_list) # 批量创建数据 book_query = models.Book.objects.all() return render(request,'bookList.html',locals())
#当数据量比较大且要展示时,页面应该考虑用分页处理 1.先用QuerySet做切片操作 2.分页样式添加 3.页码展示 如何根据总数据和每页展示的数据得出总页码? divmod(101,10) #结果为(10,1) 判断结果第二个结果如果有值就用第一个结果+1,即可知道需要的页数 a,b=divmod(101,10) if b: a+=1 print('页数:',a) 4.如何渲染出所有的页码标签 前端模板语法不支持range 但是后端支持 #我们可以在后端创建好html标签然后传递给html页面使用 5.如何限制住展示的页面标签个数 页码推荐使用奇数位(对称美 1,2,3) 利用当前页前后固定位数来限制 6.首尾页码展示范围问题 因为上一步设置了i在左边几位和右边几位中间 带一个分页器组件,但是不太好用,用我们自己写的分页器
#针对数据量大但又需要全部展示给用户观看的情况下,我们统一做法都是做分页处理 1.在app01项目文件下新建一个plugirs文件夹用来存放第三方插件 2.在plugirs文件夹下创建一个mypage.py文件并粘贴以下代码 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) 3.在views.py中 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()) 4.在html文件中 {% for book_obj in page_query %} <p class="text-center">{{ book_obj.title }}</p> {% endfor %} {{ page_obj.page_html|safe }}
编写用户登录功能并且校验数据返回提示信息(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 == '张三': data_dict['username'] = '用户名不能是张三' if password == '123': data_dict['password'] = '密码过于简单' return render(request,'ab_form.html',locals()) #以上写法不够简单!所以要用到form组件:
form 组件就是在html页面中利用from表单向后端提交数据,对用户所输入的数据与后端的数据做校验 form组件是Django中自带的一个功能,使用之前需要提前导入模块
form组件 1.数据校验 支持提前设置各种校验规则 之后自动校验 2.渲染标签/页面 支持直接渲染获取用户数据的各种标签 3.展示信息 支持针对不同的校验失败展示不同的提示
#因为form是校验表数据的,所以需提前先创建一张表 1.models.py中创建一个表 class User(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() email=models.EmailField() 2.views.py中创建一个form类 from django import forms class MyForm(forms.Form): name=forms.CharField(max_length=8,min_length=3)#最长8字符,最短3字符 age=forms.IntegerField(max_value=150,min_value=0) email=forms.EmailField()#邮箱不用给限制自动就会有邮箱格式限制
1.数据校验功能 #可以用最下面的Python Console单独测试某个py文件 #from app01 import views 1.1.传递待校验的数据 form_obj = views.MyForm({'name':'jason','age':18,'email':123}) 1.2.判断所有的数据是否符合校验条件 form_obj.is_valid()#有错误则返回False #False 1.3.获取符合校验规则的数据 form_obj.cleaned_data #{'name': 'jason', 'age': 18} 1.4.获取不符合校验规则的数据及错误原因 form_obj.errors #{'email': ['Enter a valid email address.']} """ 1.form类中编写的字段默认都是必填的 少传则不通过校验 2.校验如果多传了字段 则不参与校验 全程忽略 """ 2.渲染标签/页面功能 2.1.方式1(封装程度高 扩展性差) {{ form_obj.as_p }} {{ form_obj.as_table }} {{ form_obj.as_ul }} 2.2.方式2(封装程度低 扩展性好 编写困难) {{ form_obj.name.label }} {{ form_obj.name }} 2.3.方式3(推荐使用) {% for form in form_obj %} <p>{{ form.label }}{{ form }}</p> {% endfor %} """ 类中以外的所有标签都不会自动渲染 需要自己编写(比如提交按钮) """ 3.展示提示信息 #form表单如何取消浏览器自动添加的数据校验功能:novalidate让前端浏览器不做校验 【html中】 <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="提交"> 【views.py中】 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())
form组件中重要字段参数 max_length、min_length 校验最大长度、最小长度 max_value、min_value 校验最大数值、最小数值 label 定义字段名字 error_messages 定义报错提示 required 字段是否为空(Falsh:可以不写 True:要写) widget 标签类型、标签属性#可在字段中直接修改默认的css样式 initial 定义默认值 validators 校验正则#用该字段需导模块: #from django.core.validators import RegexValidator
#提供自定义的校验方式 #钩子函数是在字段校验完毕之后进行的第二层校验,钩子的方法名是固定的 1.【局部钩子】:校验单个字段 class MyForm(forms.Form): '''第一层校验''' name = forms.CharField(max_length=8, min_length=3, label='用户名') pwd = forms.IntegerField(label='密码') confirm_pwd = forms.IntegerField(label='确认密码') age = forms.IntegerField() email = forms.EmailField() '''第二层校验''' # 1.校验用户名是否已存在 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 # 2.校验两次密码是否一致 def func(request): form_obj = MyForm() print(form_obj.fields) if request.method == 'POST': form_obj = MyForm(request.POST) if form_obj.is_valid(): res = form_obj.cleaned_data res.pop('confirm_pwd') print(res) models.User.objects.create(**res) return render(request,'func.html',locals()) 2.【全局钩子】:校验多个字段 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
modelform是form的优化版本 '使用更简单 功能更强大' class MyModelForm(forms.ModelForm): class Meta: model = models.User #对哪张表做数据校验 fields = '__all__' #对该表所有字段做校验 labels = {} # 给每个字段加名字 widgets = {} # 给每个字段加属性 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
每个ModelForm还具有一个save()方法。 这个方法根据表单绑定的数据创建并保存数据库对象。 ModelForm的子类可以接受现有的模型实例作为关键字参数instance;如果提供此功能,则save()将更新该实例。 如果没有提供,save() 将创建模型的一个新实例: class MyModelForm(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 md(request): modelform_obj = MyModelForm() if request.method == 'POST': # edit_obj = models.User.objects.filter(name='jason').first() # modelform_obj = MyModelForm(request.POST,instance=edit_obj) 获取修改对象之后再次使用save()方法是修改 modelform_obj = MyModelForm(request.POST) if modelform_obj.is_valid(): modelform_obj.save() # 保存数据 return render(request,'ab.html',locals())
作业
1.整理今日内容及博客 2.自行尝试使用分页器、form组件、modelform组件编写数据增删改查