目录
1. 批量插入数据
def index(request): # 1.往书籍表中插入数据 1000 for i in range(1000): # 这种插入方式 效率极低 models.Book.objects.create(title=f'第{i}本书') book_list = [] for i in range(1000): book_list.append(models.Book(title=f'第{i}本书')) models.Book.objects.bulk_create(book_list) # 2.将刚刚插入的数据查询出来展示到前端 book_queryset = models.Book.objects.all() return render(request,'index.html',locals())
2. 自定义分页器
2.1 简易版手写分页器
from app01 import models def index(request): # 1.获取用户想要访问的页码数 current_page = request.GET.get('page',1) # 如果没有page参数 默认就展示第一页 # 转成整型 current_page = int(current_page) # 2.每页展示10条数据 page_num = 10 # 3.定义起始位置和终止位置 start_page = (current_page - 1) * page_num end_page = current_page * page_num # 4.统计数据的总条数 book_queryset = models.Book.objects.all() all_count = book_queryset.count() # 5.求数据到底需要多少页才能展示完 page_num,more = divmod(all_count,page_num) if more: page_num += 1 # page_num就决定了 需要多少个页码 page_html = '' inp = current_page # inp就是用户点击的数字 if current_page < 6: current_page = 6 for i in range(current_page-5,current_page+6): if inp == i: page_html += f'<li class="active"><a href="?page={i}">{i}</a></li>' else: page_html += f'<li><a href="?page={i}">{i}</a></li>' book_queryset = book_queryset[start_page:end_page] return render(request,'index.html',locals()) """ 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 """ # index.html ''' {% 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> '''
2.2 自定义分页器的使用
# 1. 在app01文件夹下新建一个utils.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: 最多显示的页码个数 用法: 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) # 2. views.py from app01.utils 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()) # login.html ''' {% for book_obj in page_queryset %} <p>{{ book_obj.title }}</p> {% endfor %} {{ page_obj.page_html|safe }} '''
3. 创建多对多表关系的三种方式
''' 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')) 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.后面字段的顺序 由第三张表通过哪个字段查询单表 就把哪个字段放前面 """ 在设计项目的时候 一定要给自己留后路 防止后续的迭代更新 """ '''
4. form校验组件
注册功能:
用户输入的用户名中 不能包含呵呵呵
如果包含了 就提示用户 输入的内容不符合社会主义核心价值观
用户输入的密码 不能小于三位
如果密码少于三位 提示用户 密码太短了
''' 1.搭建前端页面 >>> 渲染页面 2.获取前端用户提交的数据校验 >>> 校验数据 3.对数据的校验的结果 展示到前端页面给用户查看 >>> 展示错误信息 ''' def reg(request): back_dic = {'username':'','password':''} if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if '呵呵呵' in username: back_dic['username'] = '不符合社会主义核心价值观' if len(password) < 3: back_dic['password'] = '长度不能少于三位' return render(request,'reg.html',locals()) # reg.html ''' <form action="" method="post"> <p>用户名:<input type="text" name="username"> <span>{{ back_dic.username }}</span></p> <p>密码:<input type="password" name="password"> <span>{{ back_dic.password }}</span></p> <p><input type="submit"></p> </form> ''' ''' form组件能够自动帮你完成上面的三件事 1.渲染页面 2.校验数据 3.展示错误信息 '''
4.1 form组件的使用
from django import forms from django.forms import widgets from django.core.validators import RegexValidator class MyRegForm(forms.Form): username = forms.CharField(min_length=3,max_length=8,label='用户名', error_messages={ 'min_length':'用户名长度不能少于三位', 'max_length':'用户名长度不能超过八位', 'required':'用户名不能为空' },initial='请输入用户名',required=False, # 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':'密码不能为空' },initial='请输入密码', widget = widgets.PasswordInput(attrs={'class':'form-control'}) ) re_password = forms.CharField(min_length=3,max_length=8,label='确认密码', error_messages={ 'min_length':'确认密码长度不能少于三位', 'max_length':'确认密码长度不能超过八位', 'required':'确认密码不能为空' },initial='请确认密码', widget = widgets.PasswordInput(attrs={'class':'form-control'}) ) email = forms.EmailField(label='邮箱',error_messages={ 'required':'邮箱不能为空', 'invalid':'邮箱格式不正确' },initial='请输入邮箱',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() ) ''' 改变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.core.validators import RegexValidator class MyForm(Form): user = forms.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')], ) ''' def form_reg(request): # 1.生成一个空的对象 form_obj = MyRegForm() if request.method == 'POST': # 2.获取用户提交的数据 # print(request.POST) # request.POST 其实也可以看成是一个字典 # 3.借助于form组件帮助我们校验 form_obj = MyRegForm(request.POST) # 由于request.POST其实就是一个大字典 所以直接当做参数传入即可 # 4.判断用户输入的数据是否符合校验规则 if form_obj.is_valid(): return HttpResponse('上传的数据没有问题') return render(request,'form_reg.html',locals())
4.2 校验数据
from app01 import views # 1.给自定义的类传一个字典 obj = views.MyRegForm({'username':'wzh','password':12,'re_password':125,'email':'123'}) # 2.判断数据是否全部合法 obj.is_valid() # 只有数据全部符合要求才会是True False # 3.查看符合校验规则的数据 obj.cleaned_data {'username': 'wzh', 're_password': '125'} # 4.查看不符合条件的数据以及不符合的原因是什么 obj.errors {'password': ['密码长度不能少于三位'], 'email': ['邮箱格式不正确']} # 5.校验数据的时候 默认情况下类里面所有的字段都必须传值 obj = views.MyRegForm({'username':'wzh','password':12345,'re_password':12345,'email':'123@qq.com'}) obj.is_valid() True obj = views.MyRegForm({'username':'wzh','password':12345,'re_password':12345}) obj.is_valid() False obj.errors {'email': ['邮箱不能为空']} # 6.默认情况下可以多传 但是绝对不能少传 obj = views.MyRegForm({'username':'wzh','password':12345,'re_password':12345,'email':'123@qq.com','aaa':'zzz'}) obj.is_valid() True
4.3 渲染页面
{#forms组件只会帮你渲染获取用户输入(输入,选择,下拉框...)的标签 提交按钮需要你自己手动写#} {#<p>三种渲染前端页面的方式</p>#} {#<p>第一种渲染前端页面的方式:封装程度太高了 标签样式及参数不方便调整 可扩展性差(不推荐使用)</p>#} {{ form_obj.as_p }} {{ form_obj.as_ul }} {#<p>第二种渲染页面的方式:扩展性较高 不足之处在于 需要你手写的代码量比较多(不推荐使用)</p>#} {{ form_obj.username.label }}{{ form_obj.username }} {{ form_obj.password.label }}{{ form_obj.password }} {{ form_obj.email.label }}{{ form_obj.email }} {#<p>第三种渲染前端页面的方式:代码量和扩展性都很高(推荐使用)</p>#} <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>
6. forms组件钩子函数
# 针对字段 你还可以做额外的校验 需要通过钩子函数 # 局部钩子 # 当你需要对某一个字段数据进行额外的一些列校验 你可以考虑使用钩子函数 # 针对单个字段的 使用局部钩子 def clean_username(self): username = self.cleaned_data.get('username') if '呵呵呵' in username: # 给username字段下面提示错误信息 # raise ValidationError('用户名不符合社会主义核心价值观') self.add_error('username','用户名不符合社会主义核心价值观') return username # 全局钩子 # 针对多个字段的校验 使用全局钩子 eg:校验两次密码是否一致 def clean(self): password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('re_password') if not password == re_password: self.add_error('re_password','两次密码不一致') return self.cleaned_data
来源:https://www.cnblogs.com/yushan1/p/11761888.html