ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python学习Day63

2022-09-08 23:32:56  阅读:271  来源: 互联网

标签:obj name form python self 校验 学习 Day63 page


Day 63

今日内容概要

  • 批量操作数据
    • 批量数据展示—分页展示
  • 自定义分页器
  • form组件
    • form组件前戏
    • form组件简介
    • form组件三大功能
    • form类型创建
    • form组件三大功能如何使用
    • form组件中重要字段参数
    • form组件中的钩子函数
  • modelform组件
    • save()方法

今日内容详细

1.批量操作数据

当使用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.1.批量数据展示——分页展示

#当数据量比较大且要展示时,页面应该考虑用分页处理
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在左边几位和右边几位中间
带一个分页器组件,但是不太好用,用我们自己写的分页器

2.自定义分页器

#针对数据量大但又需要全部展示给用户观看的情况下,我们统一做法都是做分页处理
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 }}

4.form组件

1.form组件前戏:
编写用户登录功能并且校验数据返回提示信息(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组件:
2.form组件简介
form 组件就是在html页面中利用from表单向后端提交数据,对用户所输入的数据与后端的数据做校验
form组件是Django中自带的一个功能,使用之前需要提前导入模块
3.form组件三大功能:
form组件
    1.数据校验
        支持提前设置各种校验规则 之后自动校验
    2.渲染标签/页面
        支持直接渲染获取用户数据的各种标签
    3.展示信息
        支持针对不同的校验失败展示不同的提示
4.form类型创建:
#因为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()#邮箱不用给限制自动就会有邮箱格式限制
5.form组件三大功能如何使用
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())
6.form组件中重要字段参数
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
7.form组件中的钩子函数
#提供自定义的校验方式
#钩子函数是在字段校验完毕之后进行的第二层校验,钩子的方法名是固定的

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

5.modelform组件

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
5.1.modelform组件中的save()方法
    每个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组件编写数据增删改查

标签:obj,name,form,python,self,校验,学习,Day63,page
来源: https://www.cnblogs.com/Oreoxx/p/16671192.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有