Django 分页器与Forms组件

文章目录

  • Django 分页器与Forms组件
    • 批量插入
    • 自定义分页器
      • 1. 自定义分页器思路
      • 2. 自定义分页器源码及使用
    • Forms组件
      • 1. Forms组件介绍
      • 2. Forms组件基本使用
      • 3. 校验数据
      • 4. 渲染标签
      • 展示提示信息
      • 钩子函数(HOOK)
      • forms组件其他参数及补充知识点

Django 分页器与Forms组件

批量插入

  • ORM批量插入数据处理(bulk_create)
def ab_pl(request):
    book_list = []
    for i in range(10000):
        book_obj = modes.Book(name = '第%s本书' % i)
        book_list.append(book_obj)
	# 批量插入数据时, 使用bulk_create能够大大减少操作        
    models.Book.objects.bulk_create(book_list)        

自定义分页器

  • Django也有内置的分页器模块 但是功能较少代码繁琐不便于使用

1. 自定义分页器思路

1. queryset对象是可以直接切片操作的,因此可以通过切片来控制数据的展出
2. 确定用户要访问那一页  url?page=1
	使用page参数来获取
    current_page = request.GET.get('page',1)  # 默认是第一页
    # 获取的数据都是字符串类型需要注意类型转换
3. 自己规定每页展示多少条数据
	per_page_num = 10
4. 动态获取切片的起始和结束位置
	start_page = (current_page - 1) * per_page_num
    stop_page = current_page * per_page_num
5. 获取当前数据的总条数
	all_count = book_queryset.count()
6. 确定总共需要多少页才能展示完所有的数据
	# 利用python内置函数divmod()
    page_count , more = divmod(all_count,per_page_num)
    if more:
        page_count += 1
7. 前端模板语法没有range功能
	可以在后端写好了传递给页面
8. 针对需要展示的页码规划好到底展示多少个页码
	# 一般情况下页码的个数设计都是奇数(符合审美标准)  eg:11个页码
	在当前页减56 确保当前页处于中间位置
    可以添加高亮显示
9. 针对页码小于6,处于最后6页的情况下    做特殊处理

2. 自定义分页器源码及使用

注意事项:

在Django框架中,当我们使用非Django内置的第三方功能或者组件代码的时候

通常会建立一个utils文件夹,在该文件夹内对模块进行功能性划分,(utils可以在每个应用下创建,具体)结合实际情况

下方自定义分页器是基于bootstrap样式来的 所以需要你提前导入bootstrap

  • 分页器源码
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('''
                    
                                           
                                       ''')
        return ''.join(page_html_list)
  • 后端核心代码
def add_book(request):
    # 获取所有的book对象
    book_queryset = models.Book.objects.all()
    # 默认是第一页
    current_page = request.GET.get('page',1)
    # 统计有多少个book对象
    all_count = book_queryset.count()
    # 传值生成对象
    page_obj = Pagination(current_page=current_page,all_count=all_count)
    # 将page_queryset传递到页面
    page_queryset = book_queryset[page_obj.start:page_obj.end]
    return render(request, 'book_list.html',locals())
  • 前端核心代码
{% for book_obj in page_queryset %}
    <p>{{ book_obj.title }}</p>
{% endfor %}

{{ page_obj.page_html|safe }}
  • 效果展示

Django 分页器与Forms组件_第1张图片

Django 分页器与Forms组件_第2张图片

Forms组件

1. Forms组件介绍

forms组件主要功能是django针对前端form表单提交数据进行校验,也是用处最多的功能,另外也有着渲染html代码和展示提示信息另外两种功能

补充: 为什么数据校验非要去后端,不能在前端利用js直接完成?

  • 数据校验在前端可有可无,但是后端必须要有
  • 前端校验是弱不禁风的,可以在页面上直接修改从而跳过校验
  • 也可以利用爬虫程序绕过前端页面直接朝后端提交数据

2. Forms组件基本使用

# 写在views.py中
from django import forms


class MyForm(forms.Form):
    # username字符串类型最小3位最大8位
    username = forms.CharField(min_length=3,max_length=8)
    # password字符串类型最小3位最大8位
    password = forms.CharField(min_length=3,max_length=8)
    # email字段必须符合邮箱格式  [email protected]
    email = forms.EmailField()

3. 校验数据

  1. 测试环境的准备

    pycharm在左下方有一个python console ,是pycharm提供的测试环境
    Django 分页器与Forms组件_第3张图片

  2. 校验数据代码

from app01 import views 
1 将带校验的数据组织成字典的形式传入
form_obj = views.MyForm({'username':'xxx','password':'123','email':'123'})
2 判断数据是否合法 (.is_valied) 注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()    # False
3 查看所有校验通过的数据 (.cleaned_data)
form_obj.cleaned_data  # {'username':'xxx','password':'123'}
4 查看所有不符合校验规则以及不符合的原因
form_obj.errors  # {'email': ['Enter a valid email address.']}

5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
form_obj = views.MyForm({'username':'xxx','password':'123','email':'[email protected]','hobby':'study'})
form_obj.is_valid()  # True
6 校验数据 默认情况下 类里面所有的字段都必须传值
form_obj = views.MyForm({'username':'xxx','password':'123'}) 
form_obj.is_valid()  # False
"""
也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传
"""

4. 渲染标签

  • forms组件只会自动渲染获取用户输入的标签(input select radio checkbox),不能渲染提交按钮
  1. 后端核心代码
def index(request):
    1. 先产生一个空对象
    from_obj = MyForm()
    2. 直接将该空对象传递给html页面
    return render(request,'index.html',locals())
  1. 前端利用空对象三种渲染方式
1. 第一种:代码书写极少 封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用
    {{ form_obj.as_p }}

    {{ form_obj.as_ul }}

    {{ form_obj.as_table}}

Django 分页器与Forms组件_第4张图片

2. 第二种:可扩展性很强 但是需要书写的代码太多  一般情况下不用
   <p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
   <p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
   <p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>

Django 分页器与Forms组件_第5张图片

3. 第三种:代码书写简单 并且扩展性也高
    {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}</p>
    {% endfor %}

Django 分页器与Forms组件_第6张图片

label属性默认展示的是类中定义的字段首字母大写的形式

也可以自己修改 直接给字段对象加label属性即可

username = forms.CharField(min_length=3,max_length=8,label=‘用户名’)
Django 分页器与Forms组件_第7张图片

展示提示信息

注意:

  1. 必备条件 get请求和post传给html页面对象变量名必须一样
  2. forms组件当你的数据不合法的情况下 会保存你上次的数据

后端核心代码:

def index(request):
    # 1. 先产生一个空对象
    form_obj = MyForm()
    if request.method == 'POST':
        # 获取用户数据并校验
        """
        数据校验注意事项:
            1. 数据获取繁琐
            2. 校验数据需要构造成字典的格式传入
            ps: 但是request.POST 可以看成是一个字典
        """
        # 3. 校验数据
        form_obj = MyForm(request.POST)
        # 4. 判断数据是否合法
        if form_obj.is_valid():
            # 5. 操作合法 数据存储数据库
            return HttpResponse('OK')

    # 2. 直接将该空对象传递给html页面
    return render(request,'index.html',locals())

前端代码:

<form action="">
        {% for form in form_obj %}
            <p>{{ form.label }}:{{ form }}
             <span style="color: red">{{ form.errors.0 }}</span>
            </p>
        {% endfor %}
        <input type="submit" class="btn-info btn ">
</form>

展示效果:

Django 分页器与Forms组件_第8张图片

补充: 上图效果是浏览器附带的展示错误信息,一般不会采用而是自己定制

让浏览器不做校验方法:

<form action="" method="post" novalidate>  // 添加novalidate参数

Django 分页器与Forms组件_第9张图片

自定制错误信息:

class MyForm(forms.Form):
    # username字符串类型最小3位最大8位
    username = forms.CharField(min_length=3,max_length=8,label='用户名',
                               error_messages={
                                   'min_length':'用户名最少3位',
                                   'max_length':'用户名最大8位',
                                   'required':"用户名不能为空"
                               }
                               )
    # password字符串类型最小3位最大8位
    password = forms.CharField(min_length=3,max_length=8,label='密码',
                               error_messages={
                                   'min_length': '密码最少3位',
                                   'max_length': '密码最大8位',
                                   'required': "密码不能为空"
                               }
                               )
    # email字段必须符合邮箱格式  [email protected]
    email = forms.EmailField(label='邮箱',
                             error_messages={
                                 'invalid':'邮箱格式不正确',
                                 'required': "邮箱不能为空"
                             }
                             )

Django 分页器与Forms组件_第10张图片

钩子函数(HOOK)

钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则

在特定的节点自动触发完成响应操作

在forms组件中有两类钩子

  1. 局部钩子

    给单个字段增加校验规则的时候可以使用

  2. 全局钩子

    当需要给多个字段增加校验规则的时候使用

# 局部钩子
    def clean_username(self):
        # 获取到用户名
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示错误信息
            self.add_error('username','光喊666是不行滴~')
        # 将钩子函数钩去出来数据再放回去
        return username

# 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not confirm_password == password:
            self.add_error('confirm_password','两次密码不一致')
        # 将钩子函数钩出来数据再放回去
        return self.cleaned_data

forms组件其他参数及补充知识点

label		字段名
error_messages  自定义报错信息
initial  默认值
required  控制字段是否必填
"""
1.字段没有样式
2.针对不同类型的input如何修改
	text
	password
	date
	radio
	checkbox
	...
"""
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
# 多个属性值的话 直接空格隔开即可

# 第一道关卡里面还支持正则校验
from django.core.validators import RegexValidator
validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字'),
            RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
        ]
  • 其他类型渲染
# radio
    gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )
# select
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )
# 多选
    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
# 单选checkbox
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
# 多选checkbox
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

你可能感兴趣的:(#,Django框架,django,python,后端)