批量数据操作

1.批量数据添加方式

  1.1 通过create添加
      产生数据后持续性向数据库添加数据 容易导致数据库崩掉(数据过多不适用)
     def func(request):
    for i in range(10000):
         models.Func.objects.create(num=f'第{i}张') # 持续添加数据量过大容易导致系统崩掉
    func_list = models.Func.objects.all()
    return render(request, 'func.html', locals())
     {% for func in func_list %}
         <p>{{ func.num }}</p>
      {% endfor %}
  1.2 通过bulk_create添加
      先产生所有数据 一次性添加至数据库(适用于批量数据处理)
    def func(request):
    # func_list = []                      # 创建空列表存放数据对象
    # for i in range(100000):
    #     func_obj = models.Func(num=f'第{i}张')
    #     func_list.append(func_obj)       # 添加产生的数据对象至列表
    # 上述四行可以写成列表生成式
    func_list = [models.Func(num=f'第{i}张') for i in range(100000)]
    models.Func.objects.bulk_create(func_list)
    func_list = models.Func.objects.all()
    return render(request, 'func.html', locals())

分页器操作

自定义分页器

1.分页器推导流程

1.获取所有数据并用count进行条数计算
2.对批量数据进行分页展示(获取的数据是列表套对象 可以采用切片操作)
3.规定每页显示的条数
4.设置分页
5.获得总分页数用divmod获得整数与余数(有余数则总页数=整数+1)
6.获取用户选择的页数(用异常捕获对值错误页数保持在第一页)
7.设置页面起始数据条数并展示到前端页面
  start_num = (用户选择的页数-1)*每页展示条数
  end_num = 用户选择的页数*每页展示条数
8.前端html页面无法进行总页数循环展示(无range操作)在后端写好后传入
9.在后端逻辑层面编写所有分页展示代码编写(可以设置成奇数展示 对称)
  设置传入前端页面的分页数等于空字符串
  规定每页的分页数(用用户选择的页码数对起始终止位置进行设置 如起始=用户选择页-3 终止=用户页+4)
  存在问题:起始第4条与终止第3条会出现负数页码及无数据情况
  解决办法:在逻辑编写分页展示之前进行用户选择与起始4条及终止3条页面数据比对判断(前面先设置变量=用户选择页面 如果小于起始第四条或大于终止第三条 则使展示页在此基础上不再发生改变)
  for循环获取每页上面分页数 对于用户选择的页数进行标识(用class="active"方便查看)

2.分页器推导代码

视图层代码:
def func(request):
    # 获取用户选择的页数
    choice_page = request.GET.get('page', 1)   # 网址后缀后面写?page=页数可以切换
    try:
        choice_page = int(choice_page)
    except ValueError:
        choice_page = 1
    func_list = models.Func.objects.all()
    # 确定每页展示条数
    reveal_page = 10
    # 获取页面起始条数
    start_page = (choice_page-1)*reveal_page
    end_page = choice_page*reveal_page
    page_list = models.Func.objects.all()[start_page:end_page]       # 可以通过索引取值获取展示页数
    # 获取总的条数
    sum_num = func_list.count()
    # 获取总页数
    int_page, float_page = divmod(sum_num, reveal_page)
    print(int_page)
    # 判断是否存在余数
    if float_page:
        int_page += 1
    # html中没有range操作 不能直接循环展示页面 所在在后端操作好之后传给前端页面
    html_page = ''
    # for page in range(1, int_page+1):         # 展示的是所有分页签  需要控制数量 不能在用所有页变量 可以使用用户选择的页数加一定数量表示
    user_choice_page = choice_page
    if choice_page < 4:
        user_choice_page = 4
    if choice_page > int_page-3:
        user_choice_page = int_page-3
    for page in range(user_choice_page-3, user_choice_page+4):  # 这样操作前三页 及后三页会存在负页及没有数据问题
        if page == choice_page:
            html_page += '<li class="active"><a href="?page=%s">%s</a></li>' % (page, page)
        else:
            html_page += '<li><a href="?page=%s">%s</a></li>' % (page, page)
    return render(request, 'func.html', locals())
模板层代码:
 {% for func in page_list %}
     <p class="text-center">{{ func.num }}</p>
 {% endfor %}
  </li>
  	{{ html_page|safe }} <!--需要安全校验-->
 <li>
 模型层代码:
     urlpatterns = [
        path('admin/', admin.site.urls),
        path('func/', views.func)
    ]

3.自定义分页器代码

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())

{% for book_obj in page_query %}
	<p class="text-center">{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}

form组件

简介

1.数据校验:支持提前设置各种校验规则 之后自动校验
2.渲染页面:支持直接渲染获取用户数据的各种标签
3.展示信息:支持针对不同的校验失败展示不同的提示
4.用户信息校验:

路由层代码:
urlpatterns = [
    path('admin/', admin.site.urls),
    path('userinfo/', views.userinfo)
]
视图层代码:
def userinfo(request):
    # 设置一个空的键值对
    info_dict = {'username': '', 'password': ''}
    # 获取用户输入的信息
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        email = request.POST.get('email')
        # 对用户输入的数据做校验
        if username == 'lili':
            info_dict['username'] = 'lili用户名不可以使用'
        if password == '123':
            info_dict['password'] = '笨蛋密码太简单了吧 咋和你的脑回路一样简单'
    return render(request, 'userinfo.html', locals())
模板层代码:
         <form action="" method="post">
                <p>用户名:
                    <input type="text" name="username">
                    <span style="color: red">{{ info_dict.username }}</span>
                </p>
                <P>密码:
                    <input type="text" name="password">
                    <span style="color: red">{{ info_dict.password }}</span>
                </P>
                <p>
                    <input type="submit" value="提交">
                </p>
            </form>

5.form组件创建

    # 编写form类
    from django import forms


    class MyForm(forms.Form):
        name = forms.CharField(min_length=3, max_length=8)
        age = forms.IntegerField(min_value=0, max_value=110)
        email = forms.EmailField()

数据校验

1.数据校验功能
1.1 传递待校验的数据:
1.2 判断所有数据是否符合校验:form_obj.is_valid()
1.3 获取符合校验规则的数据:form_obj.cleaned_data
1.4 查询不符合校验规则的数据及错误原因:form_obj.errors
2.代码操作:

  # 编写form类
from django import forms

class MyForm(forms.Form):
    name = forms.CharField(min_length=3, max_length=8)
    age = forms.IntegerField(min_value=0, max_value=110)
    email = forms.EmailField()
 from app01 import views
form_obj = views.MyForm({'name':'lili', 'age': 18, 'email':123})
form_obj.is_valid()    # False   判断所有数据是否正确
form_obj.cleaned_data  # {'name': 'lili', 'age': 18}   正确数据
form_obj.errors        # {'email': ['Enter a valid email address.']}  错误数据

渲染标签功能

1.渲染标签

 1.1 封装程度高 扩展性差
    {{ form_obj.as_p }}      # 产生p标签及input框 分行展示
    {{ form_obj.as_table }}  # 产生input框 一行展示
    {{ form_obj.as_ul }}     # 产生input框 产生列表表示(无序列表)
 1.2 封装程度低 扩展性好 编写困难
	{{ form_obj.name.label }}  # 产生所点字段名大写
     {{ form_obj.name }}        # 产生input框
 1.3 封装程度低 扩展性好
	{% for form in form_obj %}        # for循环展示所有数据字段
        <p>{{ form.label }}{{ form }}</p>    # 产生所有数据字段名大写   产生input框
    {% endfor %}
注:类以外的标签不会被自动渲染 需要自己编写

展示提示信息

1.展示信息:通过form表单取消浏览器自动添加的数据校验功能
2.代码操作:

路由层代码:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('user_info/', views.user_info)
    ]
视图层代码:
    def user_info(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, 'user_info.html', locals())
模板层代码:
    <form action="" method="post" novalidate>   # 转换请求类型 取消前端数据校验
        {% for form in form_obj %}
            <p>{{ form.label }}{{ form }}
            <span style="color: red">{{ form.errors.0 }}</span>     # form.errors.0 取值
            </p>
        {% endfor %}
        <p>
            <input type="submit" value="提交">
        </p>

字段常见参数

字段参数 作用
max_length 最大长度
min_length 最小长度
label 字段注释
error_messages 错误提示
required 是否为空
widget 标签类型、标签属性
initial 默认值
validators 正则校验

钩子函数

局部钩子

1.局部钩子:校验单个字段
2.代码操作:

class MyForm(forms.Form):
    name = forms.CharField(min_length=3, max_length=8)
    age = forms.IntegerField(min_value=0, max_value=110)
    email = forms.EmailField()
    pwd = forms.IntegerField()
    confirm_pwd = forms.IntegerField()

    def clean_name(self):
        name =self.cleaned_data.get('name')
        res = models.UserInfo.objects.filter(name=name).first()
        if res:
            return self.add_error('name', '已经注册过啦 傻了吗?')  
        return name     # 用完记得还回去呀


    def user_info(request):
        form_obj = MyForm()
        if request.method == 'POST':
            form_obj = MyForm(request.POST)
            if form_obj.is_valid():
                res = form_obj.cleaned_data
                res.pop('confirm_pwd')
                models.UserInfo.objects.create(**res)
        return render(request, 'user_info.html', locals())

全局钩子

1.全局钩子:校验多个字段

    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      # 拿出了所有数据 需要返回所有数据

源代码

1.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)
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name):            # 反射
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value
            except ValidationError as e:
                self.add_error(name, e)
2.self._clean_form()
     def _clean_form(self):
        try:
            cleaned_data = self.clean()
        except ValidationError as e:
            self.add_error(None, e)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data
3.self._post_clean()
注:在面向对象中封装特性里变量名前加括号是告诉我们不要直接访问(隐藏)
    涉及内容:面向对象 反射判断是否存在该属性与获取该属性

modelform组件

1.modelform组件是form组件的优化版本
    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
 posted on 2022-09-08 23:42  拾荒菇凉  阅读(163)  评论(0)    收藏  举报