ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

django框架-7

2022-09-08 22:32:02  阅读:247  来源: 互联网

标签:obj name form self django 框架 pager page


目录

Ajax

异步提交 局部刷新
与form表单的区别可以参考 码云 网址的注册页手机号输入框
Ajax其实是js自带的功能 不是一门新的技术点 我们学习的是jQuery封装之后版本

1.基础语法
	$.ajax({
        url:'',		控制数据的提交地址 默认是朝本页面发送
        type:'',	控制请求方式(默认是get请求)
        data:{},	组织提交的数据
        success:function(形参){
            	异步回调函数
        }
    })
2.数据编码格式
	Content-Type
    格式1:urlencoded
        数据格式:name=curry&pwd=666&hobby=read
    	django后端统一处理到request.POST中
    格式2:formdata
        数据格式:无法查阅
        django后端自动将文件数据处理到request.FILES 普通数据request.POST
    格式3:application/json
        数据格式:json格式
        django后端不会处理 在request.body中存储(bytes类型) 自己处理
语法注意事项
	data:JSO.stringify({'name':'curry','pwd':666}),
        contentType:'application/curry',
            
3.ajax携带文件数据
$('#d3').click(function (){
    1.产生内置对象
    let formData = new FormData();
    2.添加普通数据
    formData.append('username',$('#d1').va1())
    3.添加文件数据
    fromData.append('file',$('#d2')[0].files[0])
    4.发送Ajax请求
    $.ajax({
        url:'',
        type:'post',
        data:formData,
        contentType:false,	不使用任何编码
        processDate:false, 	不处理数据对象
        success:function(args) {
            
        }
       })  
    })
4.回调函数
    后端跟Ajax交互 不应该再返回页面 通常情况下都是返回json格式数据
    前端针对HttpResponse和JsonResponse返回的json格式数据处理策略不同
        前者不会自动反序列化 而后者会自动反序列化
        如果想让前者也自动反序列化可以添加一个固定的参数
        	dataType:'JSON'

序列化

def ser(request):
    # 拿到用户表里面的所有的用户对象
    user_list=models.User.objects.all()
    # 导入内置序列化模块
    from django.core import serializers
    # 调用该模块下的方法,第一个参数是你想一什么样的方式序列化你的数据
    ret = serializers.serialize('json',user_list)
    return HttpResponse(ret)

批量操作数据

浏览器访问一个django路由 立刻创建10万条数据并展示到前端页面
	关键词:create(创建)、all(全部)
涉及到大批量数据的创建 直接使用create可能会造成数据库崩溃
	批量数据创建>>>:bulk_create()
	批量数据修改>>>:bulk_update()
def index(request):
    for i in range(10000):
        book_obj = models.Book(title=f'第{i}本书')
        book_list,append(book_obj)
'''上述四行可以简写为一行>>>:列表生成式(列表表达式)'''
models.Book.objects.bulk_create(book_list)  # 批量创建数据
book_query = models.Book.objects.all()
return render(request,'bookList.html',locals)

批量数据展示

当数据量比较大的时候 页面展示应该考虑分页
1.QuerySet切片操作
2.分页样式添加
3.页码展示
	如何根据总数据和每页展示的数据得出总页码
    divmod()
4.如何渲染出所有的页码标签
	前端模板语法不支持range 但是后端支持 所以我们用到之前的思路咱不用 可以在后段创建好html标签然后传递给html页面使用
5.如何限制住展示的页面标签个数
	页码推荐使用奇数位(因为对称)  利用当前页前后固定位数来限制
6.首尾页码展示范围问题
"""
上述是分页器组件的推导流程 我们无需真正编写
	django自带一个分页器组件 但是不太好用 自己写一个 直接用就行
"""

自定义分页器

自定义封装页码:
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:  最多显示的页码个数
        """
        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)
前端:
{% for book_obj in page_query %}
	<p class="text-center">{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}

后端:
from app01.plugins import mypage
book_query = models.Book.objects.all()
page_obj = mypage.Pagination(current_page=request.GET.get('page'),
                             all_count=book_query.count()
                            )
page_query = book_query[page_obj.start:page_obj.end]
return render(request, 'bookList.html', locals())

form组件

form组件的主要功能如下:
    1.生成页面可用的HTML标签
    2.对用户提交的数据进行校验
    3.保留上次输入内容
前戏:编写用户登录功能并且校验数据返回提示信息(form表单)
	def ab_form(request):
    data_dict = {'username':'','password':''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'curry':
            data_dict['username'] = '不让用curry'
        if password == '666':
            data_dict['password'] = '非要666???'
    return render(request,'ab_form.html',locals())
form类型创建
	 from django import forms

    class MyForm(forms.Form):
        name = forms.CharField(max_length=8, min_length=3)  # 用户名最长八个字符 最短三个字符
        age = forms.IntegerField(max_value=150, min_value=0)  # 年龄最小0岁 最大150岁
        email = forms.EmailField()  # 邮箱必须符合邮箱格式(至少有个@符号)
        
1.数据校验功能
	1.1.传递待校验的数据
    	form_obj = views.MyForm({'name':'jason','age':18,'email':123})
   	1.2.判断所有的数据是否符合校验
    	form_obj.is_valid()
   	1.3.获取符合校验规则的数据
    	form_obj.cleaned_data
    	{'name': 'jason', 'age': 18}
   	1.4.查阅不符合校验规则的数据及错误原因
    	form_obj.errors
    	{'email': ['Enter a valid email address.']}
 	"""
 	1.form类中编写的字段默认都是必填的 少传则肯定通不过校验 is_valid
 	2.校验如果多传了一些字段 则不参与校验 全程忽略
 	"""
2.渲染标签功能
	2.1.方式1(封装程度高 扩展性差)
    	{{ form_obj.as_p }}
 		{{ form_obj.as_table }}
       {{ form_obj.as_ul }}
 	2.2.方式2(封装程度低 扩展性好 编写困难)
    	{{ form_obj.name.lable }}
      	{{ form_obj.name }}
 	2.3.方式3(推荐使用)
    	{% for form in form_obj %}
        <p>{{ form.label }}{{ form }}</p>
    	{% endfor %}
 	"""
 	类中以外的所有标签都不会自动渲染 需要自己编写
 	"""
3.展示提示信息
	form表单如何取消浏览器自动添加的数据校验功能
    	<form action="" method="post" novalidate>
   	{% for form in form_obj %}
        <p>
            {{ form.label }}{{ form }}
            <span style="color: red;">{{ form.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit" value="提交">
   	
    def func(request):
        form_obj = MyForm()
        if request.method == 'POST':
            form_obj = MyForm(request.POST)
            if form_obj.is_valid():
                print(form_obj.cleaned_data)
        return render(request,'func.html',locals())
    
重要的字段参数
    max_length、min_length	最大小长度
    max_value、min_value	   最大小值
    label				  字段注释
    error_messages		   错误提示
    required			   是否为空
    widget				  标签类型、标签属性
    initial				  默认值
    validators			  正则校验

钩子函数
	定义:提供自定义的校验方式
 	局部钩子:校验单个字段
        def clean_name(self):
            name = self.cleaned_data.get('name')
            res = models.User.objects.filter(name=name).first()
            if res:
                return self.add_error('name','用户名已存在')
            return name
 	全局钩子:校验多个字段
        def clean(self):
            pwd = self.cleaned_data.get('pwd')
            confirm_pwd = self.cleaned_data.get('confirm_pwd')
            if not pwd == confirm_pwd:
                return self.add_error('confirm_pwd','两次密码不一致')
            return self.cleaned_data

form组件源码分析

is_valid如何校验数据进行分析。
1.查看类源码发现只要给类传参self.is_bound肯定是True,重点看self.errors
def is_valid(self):
    return self.is_bound and not self.errors
2.查看了源码发现self._errors初始化就是None 所以肯定看full_clean方法

@property
def errors(self):
    if self._errors is None:
        self.full_clean()
    return self._errors
3.查看full_clean方法,发现主要有3个方法。

def full_clean(self):
        self.cleaned_data = {}  # 创建了一个存储检查没问题的数据的空字典
        self._clean_fields()  # 校验数据
        self._clean_form()  # 封装
        self._post_clean()  # 返回
4.查看self._clean_fields方法

def _clean_fields(self):
        for name, field in self.fields.items():# 循环获取字段名和字段对象
            if field.disabled:  # 字段是否是禁用的
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))  # 如果不是禁用,获取字段对应的用户数据,进行校验
            try:  # 异常捕获
                if isinstance(field, FileField): # 文件数据
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)  # clean校验的方法
                self.cleaned_data[name] = value  # 以上校验没有问题,就上传到cleaned_data里
                if hasattr(self, 'clean_%s' % name): # 利用反射判断是否拥有clean_%s的方法,就是在获取钩子函数执行,
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value # 钩子函数不报错,添加到cleaned_data里
            except ValidationError as e:  # 钩子函数报错,添加提示保存信息
                self.add_error(name, e)
查看源码发现校验数据的整个过程内部都有异常处理机制
from django.core.exceptions import ValidationError
raise ValidationError('用户名不存在')
# 自己在clean_%s钩子函数主动抛出一个异常,也不会报错,因为钩子函数是交给_clean_fields这个方法里执行的,就算clean_%s报错也是交给了_clean_fields方法里的异常捕获处理。

modeform组件

modelform是form的优化版本 使用更简单 功能更强大 form与model的终极结合 


# 后端
class MyModelFrom(forms.ModelForm):
    class Meta:
        model = models.User
        fields = '__all__'

    def clean_name(self):
        name = self.cleaned_data.get('name')
        res = models.User.objects.filter(name=name).first()
        if res:
            self.add_error('name', '用户名已存在')
        return name

def ad(request):
    modelform_obj = MyModelFrom()
    if request.method == 'POST':
        modelform_obj = MyModelFrom(request.POST)
        if modelform_obj.is_valid():
            modelform_obj.save()
    return render(request, 'ad.html', locals())

# 前端
<form action="" method="post" class="form-row">
    {% for modelform in modelform_obj %}
        <p>
            {{ modelform.label }}{{ modelform }}
        </p>
    {% endfor %}
    <input type="submit" value="提交">
</form>

标签:obj,name,form,self,django,框架,pager,page
来源: https://www.cnblogs.com/zzjjpp/p/16671055.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有