django组件
内容概要
- 多对多三种创建方式
- django内置序列化组件(drf前身)
- ORM批量操作数据(ORM操作优化)
- 自定义分页器
- form组件
多对多三种创建方式
-
全自动创建
class Book(models.Model): title = models.CharField(max_length=32, verbose_name='书名') authors = models.ManyToManyField(to='Author') class Author(models.Model): name = models.CharField(max_length=32, verbose_name='姓名')
优势:自动创建第三张表, 并且提供了add、remove、set、clear以及正反向概念
劣势第三张表无法创建更多的字段 扩展性较差
-
全手动
class Book(models.Model): title = models.CharField(max_length=32, verbose_name='书名') class Author(models.Model): name = models.CharField(max_length=32, verbose_name='姓名') class Book2Author(models.Field): book = models.ForeignKey(to=Book, on_delete=models.CASCADE) author = models.ForeignKey(to=Author, on_delete=models.CASCADE) others = models.CharField(max_length=32, verbose_name='其他') join_time = models.DateField(auto_now_add=True, verbose_name='绑定时间')
优势:第三张表完全由自己创建,扩展性强
劣势:编写繁琐 并且不在支持add、remove、set、clear以及正方向概念
-
半自动
class Book1(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Author1', through='Book1ToAuthor1', through_fields=('book', 'author')) # 在哪个表就先填那个字段 class Author1(models.Model): name = models.CharField(max_length=32) class Book1ToAuthor1(models.Model): book = models.ForeignKey(to=Book1, on_delete=models.CASCADE) author = models.ForeignKey(to=Author1, on_delete=models.CASCADE) join_time = models.DateField(auto_now_add=True)
优势:第三张表完全由自己创建 扩展性强 正反向概念依然可见
劣势:编写繁琐 不在支持 add、set、remove、clear
django内置序列化组件(drf前身)
前后端分离的项目 视图层只需要返回json
格式的数据即可
def home_func(request):
# 1. 查询所有的数据对象
book_list = models.Books.objects.all()
# 2.封装成大字段返回
data_dict = {}
for book_obj in book_list:
temp_dict = {}
temp_dict['pk'] = book_obj.pk
temp_dict['name'] = book_obj.name
temp_dict['price'] = book_obj.price
data_dict[book_obj.pk] = temp_dict
from django.http import JsonResponse
return JsonResponse(data_dict)
序列化组件(django自带 后续学更厉害的drf)
# 导入内置序列化模块
from django.core import serializers
def home_func(request):
# 调用该模块下的方法,第一个参数是你想以什么样的
# 方式序列化你的数据
book_list = models.Books.objects.all()
res = serializers.serialize('json', book_list)
return HttpResponse(res)
批量操作数据
def home_func(request):
# 1. 往book表种中插入数据
for i in range(1, 1000):
models.Bok.objects.create(title='第%s本' % i)
from django.core import serializers
bok_list = models.Bok.objects.all()
res = serializers.serialize('json', bok_list)
return HttpResponse(res)
这只方式查了十秒还每搞完
查了八百多条数据
使用orm提供的批量插入数据
def home_func(request):
# 1. 往book表种中插入数据
book_obj_list = []
for i in range(1, 1000):
book_obj = models.Bok(title='第%s本' % i)
book_obj_list.append(book_obj)
# 使用orm提供的批量插入操作 1000条数据
models.Boks.objects.bulk_create(book_obj_list)
# 批量更新
# models.Boks.objects.bulk_update(book_obj_list)
book_queryset = models.Boks.objects.all()
from django.core import serializers
res = serializers.serialize('json', book_queryset)
return HttpResponse(res)
基本上不到一秒全部插入完
分页器思路
推到流程
-
queryset支持切片操作(整数)
-
研究各个参数之间的数学关系
每页固定展示多少条数据、起始位置、终止位置
-
自定义页码参数
page = request.GET.get('page')
-
前端展示分页器样式
-
总页码问题
divmod
方法 -
前端页面页码个数渲染问题
后端产生 前端渲染
实现
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<script src="{% static 'js_dir/jquery-1.12.4.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for foo in obj_queryset %}
<p>{{ foo.title }}</p>
{% endfor %}
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{{ html_str|safe }}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</body>
def home_func(request):
"""分页"""
# 先把数据传过去
"""
需要三个数据
起始的 从那条数据开始
结束的 到那条数据结束
展示 每页展示几行
还需要 前端传过来的 那一页
"""
page = request.GET.get('page')
if not page:
page = 1
else:
page = int(page)
obj_list_len = models.Boks.objects.all().count()
all_page, mm = divmod(obj_list_len, 15)
if mm:
all_page += 1
html_str = ''
xxx = page
if xxx < 6:
xxx = 6
elif xxx > all_page-5:
xxx = all_page-5
for i in range(xxx-5, xxx+6):
if page == i:
a = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
else:
a = '<li><a href="?page=%s">%s</a></li>' % (i, i)
html_str += a
lok = 15
start = (page-1) * lok
end = page * lok
obj_queryset = models.Boks.objects.all()[start:end]
return render(request, 'homePage.html', locals())
自定义分页器的使用
django自带的分页器模块但是使用起来很麻烦 所以我们自己封装一个
def home_func(request):
from app01.utils.mypage import Pagination
boks_queryset = models.Boks.objects.all()
current_page = request.GET.get('page')
page_obj = Pagination(current_page=current_page, all_count=boks_queryset.count())
page_queryset = boks_queryset[page_obj.start: page_obj.end]
return render(request, 'homePage.html', locals())
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
分页器
class Pagination(object): # 显示数据 页码个数
def __init__(self, current_page, all_count, per_page_num=11, 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)
form组件
form组件
- 自动校验数据
- 自动生成标签
- 自动展示信息
from django import forms
class MyForm(forms.Form):
# 字符长度 最短为 3 最长为8
username = forms.CharField(min_length=3, max_length=8)
# 年龄 最小值为 0 最大值 200
age = forms.IntegerField(min_value=0, max_value=200)
# 必须符合邮箱格式
email = forms.EmailField()
from app01 import views
obj = views.MyForm({'username': '123', 'age': 12, 'email': 123})
obj.is_valid()
False
obj.cleaned_data
{'username': '123', 'age': 12}
obj.errors
{'email': ['Enter a valid email address.']}
- 只校验类中定义的字段对应的数据 多传的根本不做任何操作
- 默认情况下类中定义好的字段都是必填的