django自带的序列化组件 代码实现序列化models.py class User(models.Model): name = models.CharField(max_length=32 ) age = models.IntegerField() gender_choice = ( ( 1, ' male ' ), ( 2, ' female ' ), ( 3, ' others ' ) ) gender = m
class User(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() gender_choice = ( (1, 'male'), (2, 'female'), (3, 'others') ) gender = models.IntegerField(choices=gender_choice) addr = models.CharField(max_length=32)views.py
from app01 import models from django.http import JsonResponse def data(request): 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 orm产生的queryset无法直接被前端识别,还是需要json格式数据(硬通货)
bejson.com
可以将json格式数据优化或者美化
序列化组件Django自带的序列化组件可以省略我们上述的操作
from app01 import models from django.http import JsonResponse 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): for i in range(100000): models.Book.objects.create(title=f'第{i}本书')
book_queryset = models.Books.objects.all()
return render(request,'many_data.html',locals())
循环插入10万条数据,频繁走数据库操作,效率极低,不推荐!!!
方式二批量插入
def many_data(request): 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())
针对上一小节批量插入的数据,我们在前端展示的时候发现一个很严重的问题,一页展示了所有的数据,数据量太大,查看不方便
针对数据量大但又需要全部展示给用户观看的情况下,我们统一做法都是做分页处理
分页推导首先我们需要明确的时候,get请求也是可以携带参数的,所以我们在朝后端发送查看数据的同时可以携带一个参数告诉后端我们想看第几页的数据
其次我们还需要知道一个点,queryset对象是支持索引取值和切片操作的,但是不支持负数索引情况
接下来我们就可以推导我们的自定义分页器步骤了
current_page = request.GET.get("page",1) # 获取用户想访问的页码 如果没有 默认展示第一页 try: # 由于后端接受到的前端数据是字符串类型所以我们这里做类型转换处理加异常捕获 current_page = int(current_page) except Exception as e: current_page = 1 # 还需要定义页面到底展示几条数据 per_page_num = 10 # 一页展示10条数据 # 需要对总数据进行切片操作 需要确定切片起始位置和终止位置 start_page = ? end_page = ? """ 下面需要研究current_page、per_page_num、start_page、end_page四个参数之间的数据关系 per_page_num = 10 current_page start_page end_page 1 0 10 2 10 20 3 20 30 4 30 40 per_page_num = 5 current_page start_page end_page 1 0 5 2 5 10 3 10 15 4 15 20 可以很明显的看出规律 start_page = (current_page - 1) * per_page_num end_page = current_page* per_page_num """数据总页面获取
如果总数据有100条,每页展示10条,总共需要10页
如果总数据有101条,每页展示10条,总共需要11页
这里需要用到一个内置方法divmod
内置方法divmod>>> divmod(100,10) (10, 0) # 10页 >>> divmod(101,10) (10, 1) # 11页 >>> divmod(99,10) (9, 9) # 10页
余数只要不是0就需要在第一个数字上加一
我们可以判断元祖的第二个数字是否为0从而确定到底需要多少页来展示数据book_queryset = models.Book.objects.all() all_count = book_queryset.count() # 数据总条数 all_pager, more = divmod(all_count, per_page_num) if more: # 有余数则总页数加一 all_pager += 1利用start_page和end_page对总数据进行切片取值再传入前端页面
book_list = models.Book.objects.all()[start_page:end_page] return render(request,'booklist.html',locals())前端页面代码编写
{% for book in book_list %} <p>{{ book.title }}</p> {% endfor %}总结推导流程
- all()结果集支持正数的索引切片
- 分页相关参数数学关系
- 后端渲染前端分页代码
- 后端限制分页展示数量
- 当页面小于6或者大于N都需要额外限制
以后可能很多地方都需要使用分页,不可能重复编写,所以封装成了模块
封装的模块可以另外创建文件夹utils里面的mypage来存储分页器模块
mypage.pyclass 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)View Code 后端
from utils import mypage book_queryset = models.Books.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="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for book in page_queryset %} <p>{{ book.title }}</p> {% endfor %} {{ page_obj.page_html|safe }} </div> </div> </div>