批量插入数据
bulk_create
# 1.往书籍表中插入数据 1000
# for i in range(1000): # 这种插入方式 效率极低
# models.Book.objects.create(title='第%s本书'%i)
book_list = []
for i in range(100000): # 时间还是很短 两者差距很大
book_list.append(models.Book(title='第%s本书'%i))
models.Book.objects.bulk_create(book_list) # 批量插入数据
# 2.将刚刚插入的数据查询出来展示到前端
book_queryset = models.Book.objects.all()
return render(request,'index.html',locals())
自定义分页器
'''
思路:
首先一个大概思路是在后端把逻辑写完之后,再在前端把数据展示出来。
1.从前端(用户点击按钮,get请求),获取用户想要访问的页面数(拿到的是字符串,需要转成int类型,后面做运算)
2.规定每页展示的数据条数
3.规定展示的起始页和终止页
4.统计数据的总条数(从数据库拿到全部数据,count一下)
5.通过一定的数学计算,判断数据要多少页才能展示完(取余数)
6.所有计算完成后,对数据对象列表进行切片操作,然后发到前端进行展示。
'''
#view.py
def index(request):
# 1.获取用户想要访问的页码数
current_page = request.GET.get('page',1) # 如果没有page参数 默认就展示第一页
# 转成整型
current_page = int(current_page)
# 2.每页展示10条数据
per_page_num = 10
# 3.定义起始位置和终止位置
start_page = (current_page - 1) * per_page_num
end_page = current_page * per_page_num
# 4.统计数据的总条数
book_queryset = models.Book.objects.all()
all_count = book_queryset.count()
# 5.求数据到底需要多少页才能展示完
page_num, more = divmod(all_count,per_page_num) # divmod(100,10)
if more:
page_num += 1
# page_num就觉得了 需要多少个页码
page_html = ''
xxx = current_page # xxx就是用户点击的数字
if current_page < 6:
current_page = 6
for i in range(current_page-5,current_page+6):
if xxx == i:
page_html += '<li class="active"><a href="?page=%s">%s</a></li>'%(i,i)
else:
page_html += '<li><a href="?page=%s">%s</a></li>' % (i, i)
book_queryset = book_queryset[start_page:end_page]
return render(request,'index.html',locals())
django封装好的分页器
## 前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</head>
<body>
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
</body>
</html>
## 后端代码
from app01.utils.mypage import Pagination
# 使用封装好的分页器代码
def login(request):
book_queryset = models.Book.objects.all()
current_page = request.GET.get('page',1)
all_count = book_queryset.count()
# 1.实例化产生对象
page_obj = Pagination(current_page=current_page,all_count=all_count)
# 2.对真实数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
return render(request,'login.html',locals())
创建多对多表关系的三种方式
创建多对多表关系的三种方式
1.全自动(推荐使用**)
好处在于 django orm会自动帮你创建第三张关系表
但是它只会帮你创建两个表的关系字段 不会再额外添加字段
虽然方便 但是第三张表的扩展性较差 无法随意的添加额外的字段
class Book(models.Model):
...
authors = models.ManyToManyField(to='Author')
class Author(models.Models):
...
2.纯手动(不推荐)
好处在于第三张表可以任意的添加额外的字段
不足之处在于orm查询的时候 很多方法都不支持 查询的时候非常麻烦
class Book(models.Model):
...
class Author(models.Models):
...
class Book2Author(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')
create_time = models.DateField(auto_now_add=True)
...
3.半自动(推荐使用******)
手动建表 但是你会告诉orm 第三张表是你自己建的
orm只需要给我提供方便的查询方法
第三种虽然可以使用orm查询方法
但是不支持使用
add()
set()
remove()
clear()
class Book(models.Model):
...
authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book','author'))
# 注意to 里面放的是表名,表示和谁连接, through表示 是通过哪张表连接的
# through_fields表示 通过什么字段进行连接的,并且第一个写的必须是,
# 通过哪个字段查询到当前字段的。
class Author(models.Model):
...
books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author', 'book'))
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
create_time = models.DateField(auto_now_add=True)
...
# 1.半自动 一定要加两个额外的参数
through='Book2Author', through_fields=('book','author')
# 2.后面字段的顺序
由第三张表通过哪个字段查询单表 就把哪个字段放前面
"""
在设计项目的时候 一定要给自己留后路 防止后续的迭代更新
"""
form校验组件
'''
#注意:
校验数据通常是前后端都有校验
前端可有可无但是后端必须有
# 需求:
注册功能
用户输入的用户名中,不能包含'我',这个字段,如果包含了,就提示用户 输入的内容不符合规范
用户输入密码,不能小于3位,如果小于3位,那么提示用户 密码长度不够
'''
'''
根据上面的需求,可以有以下思路:
1.搭建前端页面 ==> 渲染页面
2.获取前端用户提交的数据校验 ===> 检验数据
3.对数据的校验的结果 展示到前端页面给用户查看 ==> 展示错误信息
'''
##############
##自己写的版本##
##############
#前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</head>
##核心代码(input框,加一个行内标签,用于标识错误信息(红色style修饰一下),这两个放在一行)
<body>
<form action="" method="post">
<p>username:
<input type="text" name="username">
<span style="color: red"></span>
</p>
<p>password:
<input type="text" name="password">
<span style="color: red"></span>
</p>
<input type="submit">
</form>
</body>
</html>
#后端代码
def register(request):
##因为要将对象中的信息发给前端(展示错误信息),而在初始页面错误信息不应该显示,所以要在全局设置一个值为空的字典,这样,开始是Get请求,前端拿到back_dic.username就是空
back_dic = {'username': '', 'password': ''}
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
if '我'in username:
#提示信息
back_dic['password'] = '输入的内容不符合规范'
if len(password) < 3:
back_dic["username"] = '密码不能少于三位'
return render(request, 'reg.html', locals())
####################
##form组件的初次使用##
####################
'''
首先讲一下,form组件可以帮你完成,渲染页面、校验数据以及展示错误信息
'''
#1.自己先写一个类,继承forms.Form,主要是设计自己的表单样式,方便后期进行使用管理
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3, max_length=8)
password = forms.CharField(min_length=3, max_length=8)
email = forms.EmailField()
#如何渲染页面
##前端核心代码
<p>三种渲染前端页面的方式,都是用户名,密码和邮箱</p>
<p>第一种渲染前端页面的方式:封装程度太高了 标签样式及参数不方便调整 可扩展性差(不推荐使用)
{{ form_obj.as_p }} #p标签包裹
{{ form_obj.as_ul }} #li标签包裹
</p>
<p>第二种渲染页面的方式:扩展性较高 不足之处在于 需要你手写的代码量比较多(不推荐使用)</p>
<p>
# 可以通过后端设置label标签,对前端进行个性化展示
{{ form_obj.username.label }}{{ form_obj.username }}
</p>
<p>
{{ form_obj.password.label }}{{ form_obj.password }}
</p>
<p>
{{ form_obj.email.label }}{{ form_obj.email }}
</p>
<p>第三种渲染前端页面的方式:代码量和扩展性都很高(推荐使用)</p>
<form action="" method="post" novalidate>
# 这个参数是取消前端帮我们校验的信息
{% for foo in form_obj %}
<p>
{{ foo.label }}:{{ foo }}
<span style="color: red">{{ foo.errors.0 }}</span> # foo.errors得到的是错误信息的列表,这里面取第1个,就是把字符串打印出来,注意:queryset对象取值都是点出来的。
</p>
{% endfor %}
<input type="submit">
</form>
#如何校验数据
from app01 import views
# 1.给自定义的类传一个字典
obj = views.MyRegForm({'username':'jason','password':'12','email':'123'})
# 2.判断数据是否全部合法
obj.is_valid() # 只有数据全部符合要求(大小,格式符合规定)才会是True
Out[4]: False
# 3.查看符合校验规则的数据并打印出来
obj.cleaned_data
Out[5]: {'username': 'jason'}
# 4.将不符合规定的数据及其错误信息打印出来
obj.errors
Out[6]:
{
'password': ['Ensure this value has at least 3 characters (it has 2).'],
'email': ['Enter a valid email address.']
}
# 5.校验数据的时候 默认情况下类里面所有的字段都必须传值
obj = views.MyRegForm({'username':'jason','password':'123'})
obj.is_valid()
Out[12]: False
obj.errors
Out[13]: {'email': ['This field is required.']}
# 6.默认情况下可以多传 但是绝对不能少传
obj = views.MyRegForm({'username':'jason','password':'1233',
'email':'[email protected]','xxx':'ooo'})
obj.is_valid()
Out[15]: True
######################
###form组件字段的扩充###
######################
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8,label='用户名', #前端属性名展示
error_messages={ #用于把原始的英语错误信息转换成中文的错误信息
'min_length':'用户名最短三位',
'max_length':'用户名最长八位',
'required':'用户名不能为空'
},initial='我是初始值',required=True
#第一个参数设置初始值,第二个是判断是否为空,为True表示需要值,不能为空,默认是true
widget= widgets.TextInput(attrs={'class':'form-control others'}) #最后这个参数是给这个框加上一个 表单样式
password = forms.CharField(min_length=3,max_length=8,label='密码',error_messages={
'min_length':'密码最短三位',
'max_length':'密码最长八位',
'required':'密码不能为空'
},widget=widgets.PasswordInput()) #这个参数相当于<input type = 'password'> 即输入的是密文形式
email = forms.EmailField(label='邮箱',error_messages={
'invalid':'邮箱格式不正确'
},required=false, widget=widgets.EmailInput(attrs={'class':'form-control'}))#最后一个参数指的是邮箱格式得样式
phone = forms.CharField(label='手机号',validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]) #固定写法,可以按正则来约束电话号码,更详细的话遇到后直接搜索 手机号输入框 正则约束
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=widgets.RadioSelect() #表示这个是个单选框
)
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=widgets.Select() #这是个下拉形式的复选框,可以选多个
)
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=widgets.SelectMultiple() #这是个可选多个的复选框,一次性展示出来
)
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput() #复选框,可以打对勾,用于确认信息
)
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple() #这是个可以通过打对勾,选多个的复选框
)
###################
##forms组件钩子函数##
###################
'''
钩子函数,就是扩充一下错误信息的,把不符合输入框约束的错误都打印出来。
'''
#首先是在类中已经定义的字段,然后打出clean, 会自动提示(选择clean_username),这个是固定写法,前面的字段门槛过了之后,再进入这里进行判断
#下面这个是针对单个字段的局部钩子 检查用户名
def clean_username():
username = self.cleaned_data.get('username')
if '我'in username:
# 给username字段下面提示错误信息,也是固定写法
self.add_error('username', '用户名命名不规范')
return username #校验完毕之后,要返回
#下面这个是针对多个字段的全局钩子 校验两次密码输入是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致') # 错误信息直接加到该对象的error里面了
return self.cleaned_data #校验完毕,把所有正确数据返回