一括挿入データ(bulk_create)
ビューレイヤー
def index(request):
# 1.往书籍表中插入数据 1000
# 方式一: 这种插入方式,效率极低,每添加一条数据就要走一次数据库(不使用)
# for i in range(1000):
# models.Book.objects.create(title='第%s本书' %i)
# book_query = models.Book.objects.all()
# 方式二:批量插入(bulk_create),效率高
book_list = [] # 先定义一个空列表
for i in range(10000):
book_obj = models.Book(title='第%s本书' %i)
book_list.append(book_obj) # 把循环获得的对象添加到列表中
models.Book.objects.bulk_create(book_list) # 通过 bulk_create批量添加数据
return render(request, 'index.html', locals())
モデル層
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#普通插入#}
{#{% for foo in book_query %}#}
{# {{ foo.title }}#}
{#{% endfor %}#}
{#批量插入#}
{% for book in book_list %}
{{ book.title }}
{% endfor %}
</body>
</html>
カスタムページャ
手動でページャにプッシュ(こちら)
ビューレイヤー
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())
フロント
<!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 book_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{{ page_html|safe }}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</body>
</html>
カスタムページャ(ダイレクトコピーを使用して後者)
カスタムフィニッシャーを使用します
次のコード・ページをコピーし、PYファイルを置きます
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: 最多显示的页码个数
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
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 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())
フロント
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
三つの方法、多くの関係で表を作成します。
- (通常、私たちは多くの関係テーブルを作成する方法です)自動
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
authors = models.ManyToManyField(to='Author') //建立表多对多关系字段
class Author(models.Model):
name = models.CharField(max_length=32)
优势:不需要手动创建第张表
缺点:由于第三张表不是自己手动创建,也就意味着第三张表字段是固定的,无法做扩展
- ピュアマニュアル(推奨されません)
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book_Author(models.Model):
book = models.ForeignKey(to='Book') # ForeignKey 会自定给字段名添加_id
author = models.ForeignKey(to='Author') # ForeignKey 会自定给字段名添加_id
create_time = models.DateField(auto_now_add=True)
# auto_now=True, 每次对数据进行修改或保存都会触发获得最新的时间
# auto_now_add, 只有在第一次创建时会保存当前的时间,之后时间都不会改变
优点:第三张表可以任意扩展字段,扩展性高
缺点:orm查询数据麻烦,很多方法都不支持,不方便
半自動(スケーラビリティ、お勧めします)
手動でテーブルを構築しますが、ORM第三の表現が構築されている自分を伝えるために
ORMだけでデータを照会するための便利な方法を提供することが私たちを与えます
しかし、このアプローチは「の使用をサポートしていません」)(アドオンの多くの分野に多くを、()を設定し、(削除)、クリア()「」「この4つの方法
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)
authors = models.ManyToManyField(to='Author', through='Book_Author', through_fields=('book', 'author'))
'''半自动 一定要加两个额外参数
through='Book_Author': 告诉django orm 书籍表和作者表的多对多关系是通过Book_Author表来记录的
through_fields=('book','author'): 告诉django orm记录关系时通过 Book_Author表中的 book字段和author字段来记录
后面字段的顺序由第三张表通过哪个字段查询单表就把哪个字段放前面'''
class Author(models.Model):
name = models.CharField(max_length=32)
class Book_Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
create_time = models.DateField(auto_now_add=True)
フォームコンポーネント
フォームコンポーネントがどのようなものです、あなたが行うことができます
1.forms组件就是一个类,可以检测前端传过来的数据,是否合法。
例如:前端传给来的邮箱数据,判断邮件格式对不对,用户名不能以什么开头,等等 》》》校验数据
2.还可以前端页面搭建 》》》 渲染页面
3.展示错误信息 》》》 展示错误信息
1.登録機能
、ユーザが入力したユーザ名がHLMを含めることはできません
、それはコンテンツの入力を促す含まれている場合は、社会主義のコアバリュー満たしていない
ユーザーが入力したパスワードが3未満にすることはできません
パスワードは3は、ユーザのパスワードが短すぎる促し未満の場合
通常のコード・チェック・ロジックデータ
バックエンド
def reg(request):
back_dic = {'username': '', 'password': ''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if 'jpm' in username:
back_dic['username'] = '不符合社会主义核心价值观'
if len(password) < 3:
back_dic['password'] = '密码不能少于三位'
return render(request, 'reg.html', locals())
フロント
<!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>
<form action="" method="post">
<p><input type="text" name="username">
<span>{{ back_dic.username }}</span></p>
<p><input type="password" name="password">
<apan>{{ back_dic.password }}</apan></p>
<p><input type="submit" class="btn-danger"></p>
</form>
</body>
</html>
フォームコンポーネントの動作により、フォームのコンポーネントが自動的にあなたが上記の3つのことを成し遂げることができます
1.レンダリングページ
2.チェックデータ
3.ディスプレイのエラーメッセージ
フォームコンポーネントを使用します
1.構文を使用します。
from django.shortcuts import render, HttpResponse
from django import forms
#1.先写一个类,继承Form
class MyForm(forms.Form):
#定义属性,用来校验
#限制最大长度为8,最小长度为3
username = forms.CharField(min_length=3,max_length=8,label='用户名',
error_messages={
'min_length':'用户名最短三位',
'max_length':'用户名最长八位',
'required':'用户名不能为空'
},initial='我是初始值',required=False,
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())
#校验邮箱
email = forms.EmailField(label='邮箱',error_messages={
'required':'邮箱不能为空',
'invalid':'邮箱格式不正确' #(记住)
},required=False,widget=widgets.EmailInput(attrs={'class':'form-control'}))
2.在视图函数中使用MyFrom来校验数据
def formmm(request):
#实例化产生对象,将要校验的数据传入(可以传字典,也可以不传),这个数据是前端传递过来的
form_obj = Myforms()
if request.method == 'POST':
form_obj = Myforms(request.POST)
3.校验,is_valid如果是true表示校验成功,(表示满足所有条件),否则验证失败
if form_obj.is_valid():
#打印校验通过的数据
print(form_obj.cleaned_data) #{'username': 'chen', 'password': '111', 'email': '[email protected]'}
return HttpResponse('你上传的数据没问题')
else:
#校验失败的信息 是一个字典,它是所有错误信息 {错误字段名:[错误原因]}
print(form_obj.errors) # errors是一个字典,key:字段名,value:是一个列表,里面内容表示每个字段的错误信息
return HttpResponse('校验失败')
return render(request, 'formmm.html', locals())
そして、コンポーネントの動作の他のパラメータ
max_length #代表该字段最长可以为多少
min_length #代表该字段最短可以为多少
error_messages #设置错误信息的属性
required #默认值为True,意思是你前端传来的字段必须有它,没有的话校验失败,意思就是输入框必填,不能为空; 可改为False.就无需填写
label #注释信息label ='用户名' 在前端渲染可以直接对象.label获取值
initial #设置默认值
widget #控制标签属性和样式
widget = widgets.PasswordInput() #你在模板渲染的时候,就会渲染成Input框,password样式
控制标签属性
widget = widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})
#例子
pwd = forms.CharField(max_length=8,min_length=3,required=True,label='密码',
error_messages = {'max_length':'最长是8','min_length':'最短是3','required':'这个必须填'}
其他操作方式
# 单选的radio框
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
# 单选select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
# 多选的select框
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
# 单选的checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
# 多选的checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
方法:
clean_data 验证通过的数据
errors 错误数据的对象
errors.as_data 错误数据的信息
注意事項
1.自定义的类中所有的字段默认都是必须要传值的
2.可以额外传入类中没有定义的字段名,forms组件不会去校验,也就是多传没有关系3.实例化时,传入必须是字典,也可以不传
form_obj = views.LoginForm({'username':'jason','password':'123456','email':'[email protected]'})
form_obj.is_valid()
True
form_obj = views.LoginForm({'username':'jason','password':'123456'})
form_obj.is_valid() # 少传就是 False
False
form_obj = views.LoginForm({'username':'jason','password':'123456','email':'[email protected]','hobby':'read'})
form_obj.is_valid() # 多传默认是没关系的
True
エラーメッセージをレンダリング、ページのレンダリング
フォーム成分はまた、テンプレート層を考慮して使用することができます
テンプレート層
1.forms组件只会帮你渲染获取用户输入(输入,选择,下拉框...)的标签 提交按钮需要你自己手动写
#第一种渲染方式(封装程度太高,一般只用于本地测试,通常不适用)
<form action='' method='post'>
{{ myform.as_p }}
{{ myform.as_ul }}
{{ myform.as_table}}
<input type='submit' value = '提交'></input>
</form>
#第二种渲染页面的方式(可扩展性高,书写麻烦)
<form action='' method='post'>
{{myform.name.label}}:{{myform:name}}
{{myform.pwd.label}}:{{myform:pwd}}
{{myform.email.label}}:{{myform:email}}
<input type='submit' value = '提交'></input>
</form>
#第三种渲染方式(推荐)
<form action='' method='post'>
{% for foo in myform %}
<p> {{ foo.lable }} : {{ foo }}
<span>{{ foo.errors.0 }}</span> //注意后面加0 错误信息
</p>
<input type='submit' value = '提交'></input>
</form>
ビューレイヤー
def reg(request):
myform = MyForm()
if request.method == 'POST':
myform = MyForm(request.POST)
print(request.POST) #<QueryDict: {'name': ['小张'], 'pwd': ['123123'], 'email': ['[email protected]']}>
return render(request,'reg.html',locals()) #把myform对象传到前端页面了
注意事項:
1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入的标签 提交按钮需要你手动添加
2.input框的label注释 不指定的情况下 默认用的类中字段的首字母大写
フック関数(HOOK)
関数は、カスタムクラスの形式で定義することができます:フォームアセンブリがユーザーに公開され、あなたが定義されているセルフチェックルールを使用することができます
1.ローカルフック(特定のフィールドのための追加検証を行います)
名前:clean_フィールド名、内部に、検証のためのフィールドの外に、渡された場合、フィールドに戻って、それが失敗した場合は、例外をスロー
#函数名:clean_字段名字
def clean_name(self): #self是当前form对象
name = self.cleaned_data.get('name') #从验证通过的数据中再次筛选
if '666' in username:
#失败,抛异常,把异常信息以('key','value')形式写入add_error中
self.add_error('name','不能包含666')
#正常,把name返回到clean_data,将name写入clean_data字典中
return name
注意点:
- これらの機能は、チェック機能を書くclean_するフィールド名を確認する必要があるフィールド内のカスタムクラスの形で書かれています
- 辞書形式に書き込まれた:{値}キーのエラーチェックがに(「フィールド名」、「エラー」)add_errorによって、失敗しました
- チェックインは、clean_data名への復帰を成功、書かれたclean_data辞書
2.グローバルフックは、(複数のフィールドのための余分なチェックを行うために)
#重写clean方法
def clean(self):
#能走到这步,说明前面的校验已经通过了,下面校验两次两次密码是否输入一致
pwd = self.clean_data.get('pwd')
re_pwd = self.clean_data.get('re_pwd')
if pwd == re_pwd:
#校验成功,直接返回clean_data
return self.clean_data
else:
#校验失败,把错误信息放入errors中
self.add_error('re_pwd','两次密码输入不一致')
或者
#抛出异常
raise ValidationError('两次密码不一致')
注意点:
- チェックは、2個の書き込み、スロー例外があり、失敗し、例外情報がある{「すべて」:[値は、]}エラー辞書を書きます
- チェックインは、リターンclean_data辞書を成功します
- ValidationErrorをインポートをインポートdjango.core.exceptionsから、タイプValidationErrorをの例外を投げます
フックポイントをレンダリングするエラーメッセージに注意してください。
- スローされた例外のエラーメッセージがフィールドに追加されますローカルフックは、エラーメッセージが表示されます
遠位:環状オブジェクトの{{}} foo.errors.0
- 例外がスローされたグローバルフックはエラーメッセージを取得し、__all__に追加されます。
リア:myform.errors.get(「すべて『)[0]の第1判定myform.errors.getことに注意してください(』すべて」)がある場合
遠位:{{Myform.errors .__全て__ 0}}
- これらの機能は完全に準拠したデータclean_dataは、に見ているので、これらのコンポーネントは、その後、我々はclean_dataからデータを取ることができ、成功であることを示すために、フォームの前面をチェック、行くことができますが、clean_data辞書が優れています値。
フォームコンポーネントのチェックを完了
ビューレイヤー
from django.shortcuts import render, HttpResponse, redirect
# forms组件数据校验的功能
# 第一步:先要继承Form
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
# 写一个类
class MyForm(forms.Form):
# 定义一个属性,可以用来校验字符串类型
# 限制最大长度是8,最小长度是3
name = forms.CharField(max_length=8, min_length=3, label='用户名'
error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密码',
error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.PasswordInput())
re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='确认密码',
error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填'},
widget=widgets.PasswordInput())
# 校验是否是邮箱格式
email = forms.EmailField(label='邮箱', error_messages={'required': '这个必须填', 'invalid': '不符合邮箱格式'})
# aa = forms.CharField(label='选择', error_messages={'required': '这个必须填', 'invalid': '不符合邮箱格式'},widget=widgets.CheckboxInput())
def clean_name(self):
# self:当前form对象
name = self.cleaned_data.get('name')
if name.startswith('sb'):
# 失败,抛异常
raise ValidationError('不能以傻逼开头')
# 正常,把name返回
return name
def clean(self):
pwd = self.cleaned_data.get('pwd')
re_pwd = self.cleaned_data.get('re_pwd')
if pwd == re_pwd:
return self.cleaned_data
else:
raise ValidationError('两次密码不一致')
def index_form(request):
# 生成对象时(实例化),需要传入要校验的数据(字典)
if request.method == 'GET':
myform = MyForm()
return render(request,'indxe2.html',locals())
elif request.method == 'POST':
myform = MyForm(request.POST)
if myform.is_valid():
# print(myform.cleaned_data) # 验证通过的数据
# models.User.objects.create(name='lqz',pwd='123',re_pwd='123)
myform.cleaned_data.pop('re_pwd')
models.User.objects.create(**myform.cleaned_data)
return redirect('http://www.baidu.com')
else:
all_error = myform.errors.get('__all__')
if all_error:
all_error = all_error[0]
# print(myform.errors.as_data)
return render(request, 'indxe3.html', locals())
テンプレート層
<form action="" method="post" novalidate>
{% for foo in myform %}
<p>{{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span></p>
{% endfor %}
<input type="submit" value="提交"><span>{{ all_error }}</span>
</form>
その他の考慮事項
如何展示错误信息
如何取消前端帮我们做的校验 form表单中添加一个参数即可:novalidate
<form action="" method="post" novalidate>
展示错误信息 用对象点errors.0
<form action="" method="post" novalidate>
{% for foo in form_obj %}
<p>
{{ foo.label }}:{{ foo }}
<span style="color: red">{{ foo.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit">
</form>
如何改变input框的type属性值
widget= widgets.TextInput()
widget=widgets.PasswordInput()
如何让forms组件渲染出来的input框有form-control类属性
widget= widgets.TextInput(attrs={'class':'form-control others'}) # 如果有多个类属性 空格隔开
widget=widgets.PasswordInput(attrs={'class':'form-control others'})
每个字段 还支持正则校验
from django import forms
from django.forms import Form
from django.core.validators import RegexValidator
class MyForm(Form):
user = forms.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)