Django day09(自带序列化组件、批量数据操作、分页器、forms组件)

Django day09

练习

# 用户动态校验
1.前端
<p>username:
    <input type="text" id="i1">
    <span style="color: red" id="error"></span>
</p>

<script>
    $('#i1').on('input',function () {
        let iVal = $(this).val()
        $.ajax({
            url:'',
            type:'post',
            data:{'i1':iVal},
            success:function (args) {
                // 找到span标签设置文本内容
                $('#error').text(args)
            }
        })
    })
</script>

2.后端
def check_name(request):
    name_list = ['horizon', 'bloodhound', 'pathfinder', 'octane']
    if request.method == 'POST':
        username = request.POST.get('i1')
        if username in name_list:
            return HttpResponse(f'用户名已存在')
        else:
            return HttpResponse('')	# 避免返回页面数据
    return render(request, 'check_name.html')
# 删除二次校验
1.前端
<div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2"><h2 class="text-center">数据展示</h2>
                <table class="table table-hover table-striped">
                    <thead>
                        <tr>
                            <th>用户名</th>
                            <th>密码</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for v in data.values %}
                            <tr>
                                <td>{{ v.name }}</td>
                                <td>{{ v.age }}</td>
                                <td>
                                    <a href="#" class="btn btn-primary btn-xs">编辑</a>
                                    <a href="#" class="btn btn-danger btn-xs delBtn" delete_id="{{ v.pk }}">删除</a>
                                </td>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    <script>
        $('.delBtn').click(function () {
            let choiceMsg = confirm('确定删除?')
            let currentEle = $(this)
            if(choiceMsg){
                $.ajax({
                    url:'',
                    type:'post',
                    data:{'delete_id': currentEle.attr('delete_id')},
                    success:function (args) {
                        // 页面刷新(页面应该反映出删除的效果)
                        // 直接刷新页面(此处用的是数据类型 无法刷新查看  应该使用数据库数据就可以刷新查看变化)
                        {#window.location.reload()#}
                        // 通用的方式(通过DOM操作 删除一行标签内容)
                        // 好处在于页面有多页数据的情况下 删除的不是第一页数据 页面不刷新 还会停留在所处页 直观效果更好
                        currentEle.parent().parent().remove()
                    }
                })
            }
        })
    </script>

2.后端            
def check_delete(request):
    data = {'1': {'pk': '1', 'name': 'ycj', 'age': 18}, '2': {'pk': '2', 'name': 'cc', 'age': 20}}
    if request.method == 'POST':
        delete_id = request.POST.get('delete_id')
        data.pop(delete_id)
        return HttpResponse(str(data))
    return render(request, 'check_delete.html', locals())                

django自带的序列化组件

from app01 import models
from django.http import JsonResponse

def d_data(request):
    # 前后端分离之后 django orm产生的queryset无法直接被前端识别 还是需要json格式数据(硬通货)
    data_list = []  # [{}, {}, {}]
    user_queryset = models.User.objects.all()
    for user_obj in user_queryset:
        data_list.append({
            'pk':user_obj.pk,
            'name':user_obj.name,
            'age':user_obj.age,
            'gender':user_obj.gender,
            'gender_real':user_obj.get_gender_display(),
            'addr':user_obj.addr
        })
    return JsonResponse(data_list, safe=False)

Django内置的serializers

from app01 import models
from django.core import serializers

def d_data(request):
    user_queryset = models.User.objects.all()
    ret = serializers.serialize('json', user_queryset)
    return HttpResponse(ret)

批量数据操作

def many_data(request):
    # 循环插入10万条数据(频繁走数据库操作 效率极低 不推荐!!!)
    # for i in range(100000):
    #     models.Book.objects.create(title=f'第{i}本书')
    '''批量插入'''
    book_list = []
    for i in range(100000):
        # 先用类产生一个对象
        source_book_obj = models.Books(title=f'第{i}本书')
        # 将对象追加到列表中
        book_list.append(source_book_obj)
    models.Books.objects.bulk_create(book_list)  # 批量插入
    book_queryset = models.Books.objects.all()
    return render(request,'many_data.html',locals())

分页器推导流程

网站不可能将所有的数据全部展示到一页,应该考虑使用分页 每页展示一些
  1.all()结果集支持正数的索引切片
  2.分页相关参数数学关系
  3.后端渲染前端分页代码
  4.后端限制分页展示数量
  5.当页面小于6或者大于N都需要额外限制
  ...
推导过程

# 手动添加参数?page=n
def many_data(request):
    # 获取用户想要查看的页码
    current_page_num = request.GET.get('page')
    try:
        current_page_num = int(current_page_num)
    except Exception:
        current_page_num = 1
    # 每页展示的条数
    per_page_num = 10
    start_num = (current_page_num - 1) * 10
    end_num = current_page_num * per_page_num
    book_queryset = models.Book.objects.all()[start_num:end_num]
    return render(request, 'many_data.html', locals())



# 使用超链接自动向地址栏传参
<nav aria-label="Page navigation">
      <ul class="pagination">
        <li>
          <a href="#" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        <li><a href="?page=1">1</a></li>
        <li><a href="?page=2">2</a></li>
        <li><a href="?page=3">3</a></li>
        <li><a href="?page=4">4</a></li>
        <li><a href="?page=5">5</a></li>
        <li>
          <a href="#" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>


# 后端渲染前端页面代码 做分页限制
def many_data(request):
    data_queryset = models.Book.objects.all()
    # 获取用户想要查看的页码
    current_page_num = request.GET.get('page')
    try:
        current_page_num = int(current_page_num)
    except Exception:
        current_page_num = 1
    # 每页展示的条数
    per_page_num = 10
    start_num = (current_page_num - 1) * 10
    end_num = current_page_num * per_page_num
    # 前端渲染的页码数量 应与总数据相关 不能写死
    # 渲染的页面数量应该固定死 展示几个 然后动态变化
    show_num = 11
    all_count = data_queryset.count()
    page_num, more = divmod(all_count, per_page_num)
    if more:
        page_num += 1
    html = ''
    xxx = current_page_num
    if current_page_num < 6:
        xxx = 6
    elif current_page_num > 1000:
        xxx = 9995
    for i in range(xxx-5, xxx+6):     # 显示页码左右各五个页码
        if current_page_num == i:
            html += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            html += '<li><a href="?page=%s">%s</a></li>' % (i, i)

    book_queryset = data_queryset[start_num:end_num]
    return render(request, 'many_data.html', locals())
# 模板
# 新建文件夹utils-->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)

# 基本使用
from utils import mypage
    book_queryset = models.Book.objects.all()
    # 产生分页器对象
    page_obj = mypage.Pagination(current_page=request.GET.get('page'), all_count=book_queryset.count())
    # 产生分页数据对象
    page_queryset = book_queryset[page_obj.start: page_obj.end]
    return render(request, 'many_data.html', locals())


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

Forms组件

# 前戏
编写一个校验用户名和密码是否合法的功能
  前端需要自己编写获取用户数据的各种标签
  前端需要自己想方设法的展示错误的提示信息
  后端需要自己想方设法的编写校验代码(很多if判断)
  
# form组件
上面的三件事有一个人可以一次性帮你搞定>>>:form组件
  1.数据校验
  2.标签渲染
  3.展示信息

# 基本使用
from django import forms
class MyForm(forms.Form):
    # 用户名至少三个字符最多八个字符
    username = forms.CharField(min_length=3,max_length=8)
    # 年龄最小不能小于0 最大不能超过150
    age = forms.IntegerField(min_value=0,max_value=150)
    # 邮箱必须符合邮箱格式(@关键符号)
    email = forms.EmailField()

校验数据

# 基于测试环境
from app01 import views
1.将数据传入实例化对象
form_obj = views.MyForm({'username':'zero','age':18,'email':'123com'})

2.查看数据是否合法(全部合法结果才是True)
form_obj.is_valid()
# Flase

3.查看不符合条件的的数据及原因
form_obj.errors
# {'email': ['Enter a valid email address.']}

4.查看符合条件的数据
form_obj.cleaned_data
{'username': 'zero', 'age': 18}

'''
1.forms类中所有的字段默认必填
	若想忽略某些字段 可添加required=False	
2.forms类中额外传入的字段数据不会做任何的校验 直接忽略	
'''

渲染标签

渲染方式1:封装程度高 扩展性较差 主要用于快速生成页面测试功能
  {{ form_obj.as_p }}
  {{ form_obj.as_table }}
  {{ form_obj.as_ul }}
渲染方式2:封装程度低 扩展性较好 但是字段比较多的情况下不方便
  {{ form_obj.username.label }}  	# 文本提示
  {{ form_obj.username }}		# 获取用户数据的标签
渲染方式3:推荐使用!!!
  {% for form in form_obj %}
      <p>
        {{ form.label }}
        {{ form }}
      </p>
  {% endfor %}
"""
forms组件只负责渲染获取用户数据的标签
	form表单标签和提交按钮需要自己写
	<form action="" method="post">
		<input type="submit">
	</form>
渲染标签中文提示 可以使用参数 label指定 不指定默认使用字段名首字母大写
"""

展示信息

"""
forms类中填写的校验性参数前端浏览器会识别并添加校验操作
但是前端的校验是可有可无的 不能指望它!!!   后端必须要有

form表单可以取消浏览器自动添加校验功能的操作
	<form action="" method="post" novalidate></form>
"""

{% for form in form_obj %}
    <p>
        {{ form.label }}
        {{ form }}
        <span style="color: red">{{ form.errors.0 }}</span>		# 错误提示信息固定写法
    </p>
{% endfor %}
    
def ab_form(request):
    # 1.先产生一个空对象
    form_obj = MyForm()
    if request.method == 'POST':
        # 2.获取用户数据(request.POST可以看成是个大字典)
        form_obj = MyForm(request.POST)
        # 3.校验用户数据
        if form_obj.is_valid():
            # print(form_obj.cleaned_data)	查看符合条件的数据
            # models.User.objects.create(**form_obj.cleaned_data)	打散成关键字参数
            return HttpResponse('数据没问题')
    return render(request, 'ab_form.html', locals())   

# 提示信息可以自定义
	username = forms.CharField(min_length=3,max_length=8,label='用户名',
               error_messages={
                         'min_length':'用户名最短3位',
                          'max_length':'用户名最长8位',
                          'required':'用户名必填'
                               })
posted @ 2022-05-22 17:17  扶我上码  阅读(37)  评论(0)    收藏  举报