批量数据操作

浏览器访问一个django路由 立刻创建10万条数据并展示到前端页面
	create() all()

def index(request):
    for i in range(100000):
        models.Book.objects.create(title=f'第{i}本书')
    book_query = models.Book.objects.all()
    return render(request,'bookList.html',locals())

涉及到大批量数据的创建 直接使用create会非常慢甚至可能导致数据库崩溃
	批量数据创建>>>:bulk_create()
	批量数据修改>>>:bulk_update()

def index(request):
    book_list = []
    for i in range(100000):
        book_obj = models.Book(title=f'第{i}本书')
        book_list.append(book_obj)
    models.Book.objects.bulk_create(book_list)  # 批量创建
"""
上述四行可以简写成一行>>>:列表生成式
	[models.Book(title=f'第{i}本书') for i in range(100000)]
"""
    book_query = models.Book.objects.all()
    return render(request, 'bookList.html', locals())

批量数据展示

当数据量比较大的时候 页面展示应该考虑分页

1.QuerySet切片操作
2.分页样式添加
3.页码展示
	如何根据总数据和每页展示的数据得出总页码
   	可以通过内置方法 divmod()获取总页数
4.如何渲染出所有的页码标签
	前端模板语法不支持range 但是后端支持 我们可以在后端创建好html标签然后传递给html页面使用
5.如何限制住展示的页面标签个数
	页码推荐使用奇数位(对称美)  利用当前页前后固定位数来限制
6.首尾页码展示范围问题
"""
上述是分页器组件的推导流程 我们无需真正编写
	django自带一个分页器组件 但是不太好用 我们自己也写了一个
"""
代码实现
def index(request):
    book_data = models.Book.objects.all()
    # 计算总共的数据条数
    all_count = book_data.count()
    # 2.自定义每页展示的数据条数
    per_page_num = 10
    all_page_num, more = divmod(all_count, per_page_num)
    if more:
        all_page_num += 1
    # 1获取前端想要展示的页码
    current_page = request.GET.get('page')
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1
    # 后端提前生成页码标签
    html_page = ''
    xxx = current_page
    if current_page < 6:
        xxx =6
    for i in range(xxx -5, xxx + 6):
        if current_page == i:
            html_page += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)

    # 1获取前端想要展示的页码
    current_page = request.GET.get('page')
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1
    # 2.自定义每页展示的数据条数
    per_page_num = 10
    # 3.定义出切片的起始位置
    start_num = (current_page - 1) * per_page_num
    # 4.定义出切片的终止位置
    end_num = current_page * per_page_num
    book_query = models.Book.objects.all()[start_num:end_num]

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

自定义分页器

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=10, 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)
后端代码
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, 'bookList.html', locals())

前端代码
{% for book_obj in page_query %}
	<p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}

form组件

前戏:编写用户登录功能并且校验数据返回提示信息(form表单)

后端
def ad_form(request):
    data_dict = {'username': '', 'password': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason':
            data_dict['username'] = 'jason是你随便用的吗'
        if password == 123:
            data_dict['password'] = '密码就设置123???‘'
    return render(request, 'ad_form.html', locals())

前端
<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        <span style="color: red"> {{ data_dict.username }}</span>
    </p>
    <p>password:
        <input type="text" name="password">
        <span style="color: red">{{ data_dict.password }}</span>
    </p>
    <input type="submit">
</form>
form组件
1.数据校验
	支持提前设置各种校验规则 之后自动校验
2.渲染页面
	支持直接渲染获取用户数据的各种标签
3.展示信息
	支持针对不同的校验失败展示不同的提示

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=120, min_value=0)  # 年龄最大120 最小0岁
    email = forms.EmailField()  # 邮箱必须符号邮箱格式 必须有@符
    
数据校验
"""
在pycharm里面已经帮你准备一个测试环境
	python console
"""
1.将带校验的数据组织成字典的形式传入即可
	from app01 import views
	form_obj = views.MyForm({'name':'jason','age':18,'email':123})
2.判断数据是否合法 注意该方法只有在所有的数据全部合法的情况下才会返回True
	form_obj.is_valid()  # false
3.获取所有符合校验规则的数据
	form_obj.cleaned_data  # {'name': 'jason', 'age': 18}
4.查看所有不符合校验规则以及错误原因
	form_obj.errors  # {'email': ['Enter a valid email address.']}
5.校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid()  # True
6.校验数据 默认情况下 类里面所有的字段都必须传值
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()  # False
"""
1.form类中编写的字段默认都是必填的 少传则肯定通不过校验 is_valid
2.校验如果多传了一些字段 则不参与校验 全程忽略
"""
渲染标签
"""
forms组件只会自动帮你渲染获取用户输入的标签(input select radio checkbox)
不能帮你渲染提交按钮 需要自己编写
"""
后端
def index(request):
    # 1 先产生一个空对象
    form_obj = MyForm()
    # 2 直接将该空对象传递给html页面
    return render(request,'index.html',locals())
前端
方式一(封装程度高 可扩展性差 不推荐使用)
    {{ form_obj.as_p }} 
    {{ form_obj.as_ul }}  # 生成无序
    {{ form_obj.as_table }}  # 横向
方式二(封装程度低 可扩展性好 编写困难 不推荐使用)
    {{ form_obj.name.lable }}
    {{ form_obj.name }}
    {{ form_obj.age.lable }}
    {{ form_obj.age }}
方式三(编写简单 可扩展性高 推荐使用)
    {% for form in form_obj %}
        <p>{{ form.label }}{{ form }}</p>
    {% endfor %}
"""
label属性默认展示的是类中定义的字段首字母大写的形式
也可以自己修改 直接给字段对象加label属性即可
	 username = forms.CharField(min_length=3,max_length=8,label='用户名')
"""
展示提示信息
form表单自带数据校验功能
form表单如何取消浏览器自动添加的数据校验功能(关键字:novalidate)
	<form action="" method="post" novalidate>

后端
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)
        else:
            print(form_obj.errors)
    return render(request,'func.html',locals())

前端
<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">
</form>
"""
1.必备的条件 get请求和post传给html页面对象变量名必须一样
2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改
更加的人性化
"""

针对错误的提示信息还可以自己自定制
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':"用户名不能为空"
                               }
                               )
    # 年龄最大120最小0岁
    age = forms.IntegerField(max_value=120, min_value=0
                     (min_length=3,max_length=8,label='年龄',
                     error_messages={
                     'max_value': '年龄最小0岁',
                     'max_length': '年龄最大120岁',
                     'required': "年龄不能为空"
                               }
                               )
    # email字段必须符合邮箱格式  xxx@xx.com
    email = forms.EmailField(label='邮箱',
                      error_messages={
                      'invalid':'邮箱格式不正确',
                      'required': "邮箱不能为空"
                             }
                             )
重要字段参数
1.max_length与min_length
2.max_value与min_value
3.lable
	字段注释
4.error_messages
	错误信息
5.required
	是否为空
6.initial
	默认值
6.validators
	正则校验
	from django.core.validators import RegexValidator
	validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字'),
            RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
        ]
7.widget
	给标签添加类型、标签属性
	name = forms.CharField(max_length=8, min_length=3,label='用户名',
                           widget=forms.widgets.TextInput(attrs={'class':'form-control'}))  # 用户最常8个字符 最短是3个
钩子函数

提供自定义的校验方式

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','用户名已存在')
    
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组件

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


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, 'ad.html', locals())

前端
<form action="" method="post" novalidate>
    {% for foo in modelform_obj %}
        <p>
            {{ foo.label }}{{ foo }}
            <span>{{ foo.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit">

</form>
 posted on 2022-09-08 22:16  Joker_Ly  阅读(85)  评论(0)    收藏  举报