• 批量插入数据,自定义分页器,forms组件,钩子函数,forms组件重要参数,modelform组件


    一:批量插入数据

    1.urls.py

    urlpatterns = [
        # 批量插入数据
        path('index/', views.index)
    ]
    
    • 1
    • 2
    • 3
    • 4

    2.views.py

    def index(request):
        l = []
        for i in range(10000):
            l.append(models.Book(title='第%s本书' % i))
        models.Book.objects.bulk_create(l)
        return render(request, 'index.html', locals())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.html页面

    <body>
        <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                {% for book in l %}
                    <P>{{ book.title }}</P>
                {% endfor %}
            </div>
        </div>
    </div>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    总结:如何批量插入数据
    • 1.首先自定义一个空的列表
    • 2.把每一条数据通过append方法添加到自定的列表中
    • 3.最后通过bulk_create方法把自定义列表添加到数据库中
    补充知识点:

    通过bulk_update方法,实现对数据库中数据的批量修改

    二:自定义分页器(要会使用)

    1.自定义分页器代码

    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:  最多显示的页码个数
            
            用法:
            queryset = model.objects.all()
            page_obj = Pagination(current_page,all_count)
            page_data = queryset[page_obj.start:page_obj.end]
            获取数据用page_data而不再使用原始的queryset
            获取前端分页样式用page_obj.page_html
            """
            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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
如何使用自定义分页器
  • 步骤1:首相在应用文件下建一个文件夹(plugins),再在这个文件夹中建一个py文件(mypage.py),把自定义分页器代码粘贴进去
  • 步骤2:在需要分页的视图函数中写入一下代码
def index(request):
	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, 'index.html', locals())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 步骤3:在需要分页的html页面中写入以下代码
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            {% for book_obj in page_query %}
                <p class="text-center">{{ book_obj.title }}</p>
            {% endfor %}
            {{ page_obj.page_html|safe }}
        </div>
    </div>
    </div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

三:forms组件

1.forms组件具有的功能
  • 1.数据校验:支持提前设置各种校验规则,之后自动校验
  • 2.渲染画面:支持直接渲染获取用户数据的各种标签
  • 3.展示信息:支持针对不同的校验失败,展示不同的提示信息
2.forms类的产生
from django import forms

class MyForms(forms.Form):
    """下面每个字段,都必须要符合括号中的条件,或者forms组件隐藏的特点条件"""
    name = forms.CharField(min_length=3, max_length=8)
    pwd = forms.IntegerField(min_value=3, max_value=8)
    email = forms.EmailField()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
3.forms组件之数据校验

直接在pycharm自带的测试工具中测试:

from app01 import models
from app01 import views
form_obj = views.MyForms({'name':'jason','pwd':123,'email':121})

form_obj.is_valid()
False

form_obj.cleaned_data
{'name': 'jason'}

form_obj.errors
{'pwd': ['Ensure this value is less than or equal to 8.'], 'email': ['Enter a valid email address.']}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
总结:
  • 1.首先导入要测试的文件
  • 2.准备好测试数据,并且以字典的形式传入,同时生成测试对象
  • 3.object.is_valid() 该方法只有在所有的数据都合法的情况下,才会返回True
  • 4.object.cleaned_data 返回所有符合校验规则的数据
  • 5.object.errors 返回不符合校验规则的数据,以及不符合规则的原因
补充总结:
  • 1.只校验类中出现的字段,多传没影响,不会报错
  • 2.少传会直接报错
4.forms组件之渲染标签
  • 步骤1:写一个视图函数,产生一个forms类的空对象,把这个空对象直接传到html页面上
def index1(request):
    # 1.先产生一个空对象
    forms_obj = MyForms()
    # 2.直接把空对象传递给html页面
    return render(request, 'index1.html',locals())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 步骤2:在html页面中通过对象点的方式得到表中字段对应的标签
  • 方式1(封装程度高 扩展性差)
{{ form_obj.as_p }}
{{ form_obj.as_table }}
{{ form_obj.as_ul }}
  • 1
  • 2
  • 3
  • 方式2(封装程度低 扩展性好 编写困难)
 {{ form_obj.name.lable }}
 {{ form_obj.name }}
  • 1
  • 2
  • 方式3(推荐使用)
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>
{% endfor %}
  • 1
  • 2
  • 3
5.forms组件之展示提示信息

views.py

from django import forms

class MyForms(forms.Form):
    name = forms.CharField(min_length=3, max_length=8, label='用户名',
                           error_messages={
                               'min_length': '用户名最少为3个字符',
                               'max_length': '用户名最大为8个字符',
                               'required': '用户名不能为空'
                           }
                           )
    pwd = forms.CharField(min_length=3, max_length=8, label='密码')
    confirm_pwd = forms.CharField(min_length=3, max_length=8, label='确认密码')
    email = forms.EmailField(label='邮箱',
                             error_messages={
                                 'invalid': '邮箱格式不正确'
                             }

                             )

def index1(request):
    # 1.先产生一个空对象
    forms_obj = MyForms()
    if request.method == 'POST':
        # 3.校验数据
        forms_obj = MyForms(request.POST)  # request.POST 就是一个字典
        # 4.校验数据是否合法
        if forms_obj.is_valid():
            # 5.如果合法 操作数据库存储数据
            pass
        # 6.如果不合法  错误信息会展示到前端
    # 2.直接把空对象传递给html页面
    return render(request, 'index1.html',locals())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

html页面

<form action="" method="post" novalidate>
    {% for form in forms_obj %}
        <p>
            {{ form.label }}{{ form }}
        <span style="color: red">{{ form.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit">
</form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
总结:
  • 1.想要取消前端页面的校验功能,直接在form标签中加入属性:novalidate
  • 2.get请求和post请求传给html页面对象的变量名必须一样(视图函数中的两个:forms_obj要一样)
  • 3.两个form_obj的作用:forms组件当你的数据不合法的时候情况下,会保存你上次的数据,让你基于上次的基础上进行修改数据,更加的便捷
  • 4.error_message可以自定义错误提示信息
  • 5.label可以自定义字段名称,即可以定义成汉字
  • 6.由于form.errors是一个列表,所以不许点0,拿到第一条数据

四:钩子函数

注意:钩子函数必须写在forms类中

1.分类:
  • 1.局部钩子:单个字段的校验,类似于第二道校验关卡
  • 2.全局钩子:多个字段的校验,类似于第二道校验关卡
2.局部钩子案例:校验name字段
    def clean_name(self):
        # 1.获取用户名
        name = self.cleaned_data.get('name')
        if 'h' in name:
            # 提示前端展示错误信息
            self.add_error('name', '名字中不能出现h')
            # 将钩子函数勾取的数据返回回去
        return name
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
3.全局钩子案例:校验pwd和comfirm_pwd
    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        confirm_pwd = self.cleaned_data.get('confirm_pwd')
        if not pwd == confirm_pwd:
            self.add_error('confirm_pwd', '两次密码不一致')
        return self.cleaned_data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

五:forms组件重要参数

1.基本参数
参数作用
label字段注释
error_messages错误提示
required是否为空
initial默认值
validators正则校验
widget标签类型、标签属性

2.widget参数
  • input
widget=forms.widgets.TextInput(attrs={'class': 'form-control c1 c2', 'username': 'jason'})
  • 1
  • password
pwd = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • radioSelect
gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 单选select
hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 多选select
hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 单选checkbox
keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 多选checkbox
hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

总结:

  • 1.多个属性值的话,直接用逗号隔开
3.validators正则校验
RegexValidator(r'^[0-9]+$','请输入数字')
  • 1

六:modelform组件

1.modelform是forms组件的优化版本,使用更加简单

views.py

class MyModelForm(forms.ModelForm):
    class Meta:
        model = models.User
        fields = '__all__'
        exclude = ('age',)  # 把某个字段排除在外

    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':
        modelform_obj = MyModelForm(request.POST)
        if modelform_obj.is_valid():
            modelform_obj.save()  # 保存数据
    return render(request, 'md.html', locals())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

html文件

<body>
<form action="" method="post" novalidate>
{% for model in modelform_obj %}
    <p>
        {{ model.label }}{{ model }}
    <span>{{ model.errors.0 }}</span>
    </p>
{% endfor %}
    <input type="submit">
</form>
</body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11


  • 相关阅读:
    量化交易全流程(六)
    idea文件菜单打不开,pom一直在加载。有些项目一直在加载。从文件打开,d盘进不去。
    基于Java+SpringBoot+Vue民宿管理系统的设计与实现 前后端分离【Java毕业设计·文档报告·代码讲解·安装调试】
    数据结构-单链表
    Java web入门:在Idea上创建Java web项目
    自知则知之做做做做做做做做做做做做做
    【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)
    CSS动画中的贝塞尔曲线
    Window对象加载时的区别与倒计时
    Java架构师设计思想
  • 原文地址:https://blog.csdn.net/Yydsaoligei/article/details/126771289