zoukankan      html  css  js  c++  java
  • Django之内置组件

    Django组件介绍

            分页器的使用

            Form

            modelForm

            orm

            cookie和session

            中间件

            信号

    1.分页器的使用

    分页器在页面中非常常见,当数据库条数数据过多时,页面一次性显示不好看,我们就可以使用页面器,将数据分几次显示

    一个简单的分页功能,可以导入用

      page_num = request.GET.get('page','1')
        try:
            page_num = int(page_num)
            if page_num <=0:
                page_num = 1
        except Exception as e:
            page_num =1
        #总数量
        all_count = len(userlist)
        #每页显示为10 页
        per_num = 10
        #总页码数
        total_page_num, more =divmod(all_count,per_num)
        if more:
            total_page_num += 1
        #最多显示的页面数
        max_show = 11
        half_show = max_show//2
        if total_page_num < max_show:
            page_start = 1
            page_end = total_page_num
        elif page_num <= half_show:
            page_start =1
            page_end =max_show
        elif page_num + half_show > total_page_num:
            page_start = total_page_num-max_show +1
            page_end = total_page_num
        else:
            #起始页面
            page_start = page_num - half_show
            #终止页面
            page_end = page_num + half_show
        start =(page_num-1) * per_num
        end =page_num*per_num
    
        page_list = []
    
        if page_num == 1:
            page_list.append('<li class="disabled"><a>上一页</a></li>')
        else:
            page_list.append('<li ><a href="?page={}">上一页</a></li>'.format(page_num - 1))
    
        for i in range(page_start, page_end + 1):
            if i == page_num:
                page_list.append('<li class="active" ><a href="?page={}">{}</a></li>'.format(i, i))
            else:
                page_list.append('<li><a href="?page={}">{}</a></li>'.format(i, i))
            if page_num == total_page_num:
                page_list.append('<li class="disabled"><a>下一页</a></li>')
            else:
                page_list.append('<li><a href="?page={}">下一页</a></li>'.format(page_num + 1))
    
            page_html = ''.join(page_list)
    
            return render(request, 'user_list.html',
                          {'users': userlist[start:end], 'page_html': page_html})
    分页

    2.Form组件

    django框架提供了一个form类,来处理web开发中的表单相关事项.form最常做的是对用户输入的内容进行验证,为此django的forms类提供了全面的内容验证和保留用户上次输入数据的支持

    form组件的两大功能:

       ---对用户提交的内容进行验证(from表单/ajax)

       ---表留用户上次输入的内容

    form组件的几大用处:

    1.校验字段功能

    1.首先先到导入forms这个模块
    from django import forms
    2.自己写一个类,并继承forms.Form
    class Myform(forms.Form):
        #这行代码的意思,name这字段最长为8,最短为3
        name=forms.charField(max_length=8)
    
    def index(request):
        dic={'name':'zh'}
        #这里就是类的实例化,传的参数必须为一个字典
        myform =Myform(dic)
        #这是对象的绑定方式,它的返回值就是一个布尔值
        # True表示你传的dic这个字典满足form里的条件,False就是不满足
        # 我们可以通过判断它,再进行逻辑操作,比如该字段符合你的要求,再怎么操作
        if myform.is_valid():
            return HttpResponse('校验成功')
        # 走到这一步,代表当中有字段不符合要求
            # 它的返回值是一个对象,但是它继承了字典,所以你可以通过get取到错误提示
            # 对了,你传的字典的key值必须要和创建的类(Myform)要对应,并且只能多,不能少
            # name_error = myform.errors.get('name')
            # 这样你可以取到name字段出错的原因了
            name_error=myform.errors
            return HttpResponse('校验失败')
    ## 总结下:1、Myform的实例化必须传字典
                  2、is_valid()返回值是布尔类型
                  3、errors  调用这个方法,返回值是对象,你可以通过get取值
    例子

    2.渲染标签功能

    form组件可以在视图函数中使用,也可以在模板中使用

       渲染方式一:
        <form action='' method='post'>
            用户名:{{myform:name}} <br>
            <input type='submit' value = '提交'></input>
        </form>
        # 这里的{{myform:name}} 和你写input框是一样的效果,就是属性比input框多一点
    
        渲染方式二(推荐使用):
        <form action='' method='post'>
            {% for foo in myform%}
                {{ foo.lable }} : {{ foo }}  <br>
            <input type='submit' value = '提交'></input>
        </form>
        # 页面显示都是一样的,foo.lable不是用户名,是name,但是你可以在创建Myform类时
        # 在CharFiel中添加lable='用户名',这样就行了。
    
        渲染方式三:
            <form action='' method='post'>
                {{ myform.as_p }}
            <input type='submit' value = '提交'></input>
        </form>
        # 对,方式三就是这么简单,但是拓展性太差了,对不对,所以不推荐使用它
    例子

    3.渲染错误信息功能

     渲染错误信息,之前不是写了error这个方法嘛,他就是装着错误信息的对象,
        其实就是让它渲染到页面上,这不就是很简单嘛
        拿渲染方式二来举例子吧:
        <form action='' method='post'>
            {% for foo in myform%}
                {{ foo.lable }} : {{ foo }} <span>{{foo.errors.0}}</span><br>
            <input type='submit' value = '提交'></input>
        </form>
    
        # 来讲下为什么不是用get去取错误信息,首先这个foo是什么?它就是你创建的字段
        # 所以直接通过索引取值就好了,那么就应该知道foo.errors貌似就是一个列表对吧
        # 模板渲染时我在后台渲染好了,再返回到前台的,那我可以不可以将错误信息传到前台
        # 让前台执行DOM操作进行渲染呢?
        # 我觉得太麻烦,况且前端我。。。(你懂的)
    例子

    4.组件的参数配置

      其实在些Myform,下面的字段还有很多参数,我就写写大概有什么用
        max_length    # 代表该字段最长为多少
        min_length    # 代表该字段最短为多少
        error_messages # 这是设置错误信息的属性
        # 例子
        error_messages=
        {'max_length': '最长八位', 'min_length': '最短三位', 'required': '不能为空'}
        required   # 默认值为True,意思是你传来的字段必须有它,没有的话校验失败
        widget=widgets.TextInput()  # 你在模板渲染的时候,就会渲染成Input框,type为text
                                      还有其他类型的input框,自己在看看吧
        对了,在TextInput(),你可以为input添加属性,attrs={'class':'abc'}  写在括号里面
        lable   #这个是不是上面讲到了,lable='用户名'
    例子

    5.钩子

    局部钩子
        局部钩子说白了就是写一个函数,但是这个函数名必须为clean_name,这个name是可以改变的,
        你定义的类里,你想对哪个字段写钩子函数,这个name就为那个字段的名字,比如我想为password这个
        字段写钩子函数,那函数名就为clean_password,就这样。
    
        那这个局部钩子有什么用了?
            首先你的程序能走到局部钩子这一步,就说明你传的字典中的字段符合要求,这要记清楚,那么我们在
            取值就从clean_data中取就好了,clean_data里装的是符合要求的数据,是一个字典。
            我们可以从clean_data中取到相应的值再做一次逻辑处理,比如我写clean_name这个局部钩子,
            我可以拿到name,对这个name进行一些操作,名字开头不能是数字,名字中不能有有什么字符,这
            些等等,看你自己的需求,逻辑代码写好了,最后return name 就好了
            
    全局钩子
        全局钩子其实作用差不多的,每个字段你可以进行局部钩子进行逻辑书写,这些处理完成之后,有需要的话,
        你再进行全局处理,举个例子就大概能明白,你在写注册用户的时候,是不是有密码,确认密码,你可以进行
        布局钩子处理,处理完毕是不是在进行判断,判断他们是否相等,相等的话,就存到数据库中,不相等就抛个
        异常,对了对了,上面局部钩子忘记写异常,下面讲讲。
        
    
    -----1、局部钩子,全局钩子所抛出异常的类型为ValidationError,它是在下面这行代码导入
            from django.core.exceptions import ValidationError
         2、局部钩子抛出的异常会添加到该字段中的错误信息中,也就是myform.errors.get(字段名)中
         3、而全局钩子抛出的异常会添加到__all__中,myform.errors.get('__all__')中可以取到
         
    说明

    3.ModelForm

    作用:

    1.手动对单表进行增,删,改,查,手动把orm操作获取的数据渲染到模块;(阶段1)

    2.Form组件(类),自动生成标签(input,select),并对用户输入的数据做规则验证;(阶段2)

    3.ModelForm顾名思义就Form和Django的Model数据库模型结合体,可以简单,方便地对数据库进行增加,编辑操作和验证标签的生成

    使用ModelForm

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {{ form_obj.as_p }}
    {#<p>姓名:{{form_obj.name  }}</p>#}
    </body>
    </html>
    前端
    class BSForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            for filed in self.fields.values():
                if not isinstance(filed, forms.BooleanField):
                    filed.widget.attrs.update({'class': "form-control"})
    
    class RegForm(BSForm):
        re_pwd = forms.CharField(widget=forms.PasswordInput, label='确认密码')
        class Meta:
            model = models.UserProfile
            fields='__all__'                      #获取全部的
            exclude=['memo','is_active']         #删除不想要的
            labels = {
                'username': '用户名'                 #标签
            }
            widgets = {
                'password': forms.PasswordInput(attrs={'class': "form-control", 'k1': 'v1'}),
            }
            error_messages = {
                'password': {
                    'required': '必填的'
                }
            }
        def clean(self):
            pwd = self.cleaned_data.get('password', '')
            re_pwd = self.cleaned_data.get('re_pwd', '')
            if pwd == re_pwd:
                return self.cleaned_data
            self.add_error('re_pwd', '两次密码不一致')
    
            raise ValidationError('两次密码不一直')
    
    
    def reg(request):
        form_obj=RegForm()
        if request.method =="POST":
            form_obj=RegForm(request.POST)
            if form_obj.is_valid():
                # print(form_obj.cleaned_data)
                # form_obj.cleaned_data.pop('re_pwd')
                # models.UserProfile.objects.create(**form_obj.cleaned_data)
                form_obj.save()
                return  redirect(reverse('login'))
        return render(request,'reg.html',{'form_obj':form_obj})
    后端

    4.orm

    --MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库

    --ORM是'对象-关系-映射'的简称 ,主要任务是:

      *根据对象的类型生成表结构

      *将对象,列表的操作,转换为sql语句

      *将sql查询到的结果转换为对象,列表

    --这极大地减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动

    --Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表

    1.在models.py中定义模型类,要求继承自models.Model
    2.把应用加入settings.py文件的installed_app项
    3.生成迁移文件
    4.执行迁移生成表
    5.使用模型类进行crud操作
    开发流程
    在模型中定义属性,会生成表中的字段
    django根据属性的类型确定以下信息:
        当前选择的数据库支持字段的类型
        渲染管理表单时使用的默认html控件
        在管理站点最低限度的验证
    django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
    属性命名限制
        不能是python的保留关键字
        由于django的查询方式,不允许使用连续的下划线
    定义模型
    定义属性时,需要字段类型
    字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中
    使用方式
    导入from django.db import models
    通过models.Field创建字段类型的对象,赋值给属性
    对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
    字段类型
    AutoField:一个根据实际ID自动增长的IntegerField,通常不指定
    如果不指定,一个主键字段将自动添加到模型中
    BooleanField:true/false 字段,此字段的默认表单控制是CheckboxInput
    NullBooleanField:支持null、true、false三种值
    CharField(max_length=字符长度):字符串,默认的表单样式是 TextInput
    TextField:大文本字段,一般超过4000使用,默认的表单控件是Textarea
    IntegerField:整数
    DecimalField(max_digits=None, decimal_places=None):使用python的Decimal实例表示的十进制浮点数
    DecimalField.max_digits:位数总数
    DecimalField.decimal_places:小数点后的数字位数
    FloatField:用Python的float实例来表示的浮点数
    DateField[auto_now=False, auto_now_add=False]):使用Python的datetime.date实例表示的日期
    参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
    参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
    该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
    auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
    TimeField:使用Python的datetime.time实例表示的时间,参数同DateField
    DateTimeField:使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
    FileField:一个上传文件的字段
    ImageField:继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
    字段选项
    通过字段选项,可以实现对字段的约束
    在字段对象时通过关键字参数指定
    null:如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
    blank:如果为True,则该字段允许为空白,默认值是 False
    对比:null是数据库范畴的概念,blank是表单验证证范畴的
    db_column:字段的名称,如果未指定,则使用属性的名称
    db_index:若值为 True, 则在表中会为此字段创建索引
    default:默认值
    primary_key:若为 True, 则该字段会成为模型的主键字段
    unique:如果为 True, 这个字段在表中必须有唯一值
    关系
    关系的类型包括
    ForeignKey:一对多,将字段定义在多的端中
    ManyToManyField:多对多,将字段定义在两端中
    OneToOneField:一对一,将字段定义在任意一端中
    可以维护递归的关联关系,使用'self'指定,详见“自关联”
    用一访问多:对象.模型类小写_set
    定义属性
    增:
     models.UserInfo.object.create(name=new_name)
    删:
    models.UserInfo.object.get(id=xxx,None)
    models.delete()
    改:
    obj = models.UserInfo.object.get(id=xx,None)
    obj = new_xxx
    obj.save()  #相当于修改后提交数据
    查
    querylist=models.Entry.objects.all()
    print([e.title for e in querylist])
    print([e.title for e in querylist])
    
    entry = models.Entry.objects.get(id=?)
    orm操作

    5.cookie和session

    cookies是浏览器为web服务器存储的一个信息,每次浏览器从某个服务器请求页面时,都会自动带上以前收到的cookie.cookie保存在客户端,安全性较差,注意不要保存没敢信息.

      --网络登录

      --购物车

    def login(request):
        if request.method == 'GET':
            return render(request,'login2.html')
    
        if request.method == 'POST':
            u = request.POST.get('username')
            p = request.POST.get('pwd')
            dic = user_info.get(u)
    
            if not  dic:
                return  render(request,'login2.html')
    
            current_date = datetime.datetime.utcnow()
    
            current_date = current_date + datetime.timedelta(seconds=10)
            if dic['pwd'] == p:
                res = redirect('/myapp/index')
                # res.set_cookie('username',u,max_age=10)
    #对cookie设置了超时时间和安全设置          
    res.set_cookie('username',u,expires=current_date,httponly=True)
                # res.set_signed_cookie('username',u,salt="121221")
                return res
            else:
                return  render(request,'login2.html')
    登录页面

    详情页面,如果cookie 验证通过则进入index页面,否则刷新进入登录页面

    def auth(func):
        def inner(request,*args,**kwargs):
            v = request.COOKIES.get('username')
            if not v:
                return redirect('/myapp/login')
            return func(request,*args,**kwargs)
    
        return inner
    @auth
    def index(request):
    
        v = request.COOKIES.get('username')
    
        return render(request,'index2.html',{'current_user':v})
    验证

    session就是保存在后台数据或者缓存中的一个键值对,同样的存储着用户信息,为更好的保护用户隐私,其实是对前端cookie的一个升级的保护措施

    当登录成功后,会向后台数据库 与 前端 Cookie同时发放一段随机字符串,分别保存在后台的session中,前端 写到用户浏览器中,用户下次登录时候 拿着浏览器存着的sessionID当做KEY去后台数据库中匹配进行验证登录即可拿到用户相关信息,可以防止敏感信息直接暴露在浏览器上
    
    作者:TianTianBaby223
    链接:https://www.jianshu.com/p/a2d696364501
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
    实现原理

    Django下用session实现登录验证

    def sessionLogin(request):
        if request.method == "GET":
            return render(request,'sessionLogin.html')
    
        elif request.method == "POST":
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
            if user == 'root' and pwd =="123":
                #生成随机字符串
                #写到用户浏览器
                #保存到session中
                #在随机字符串对应的字典中设置相关内容...
                request.session['username'] = user
                request.session['is_login'] = True
                if request.POST.get('rmb',None) == '1':
                    request.session.set_expiry(10)
    
                return redirect('/myapp/sessionindex')
            else:
                return render(request, 'sessionLogin.html')

    详情页逻辑

    def sessionindex(request):
        #获取当前用户的随机字符串
        #根据随机字符串获取对应信息
        if request.session.get('is_login',None):
            return render(request,'sessionindex.html',{'username':request.session['username']})
        else:
            return HttpResponse('get out')

    6.中间件

    定义:介于request(请求)与response(响应)处理之间的一道处理过程,相对比较轻量级,位于web服务端与url路由层之间

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',  #一些安全设置,比如xss脚本过滤
        'django.contrib.sessions.middleware.SessionMiddleware',#session支持中间件,加入这个中间件,会在数据库中生成一个django_session的表。
        'django.middleware.common.CommonMiddleware',   #通用中间件,会处理一些url
        'django.middleware.csrf.CsrfViewMiddleware',   #跨域请求伪造中间件,加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。
        'django.contrib.auth.middleware.AuthenticationMiddleware',  #用户授权中间件。他会在每个HttpRequest对象到达view之前添加当前登录用户的user属性,也就是你可以在view中通过request访问user。
        'django.contrib.messages.middleware.MessageMiddleware',#消息中间件。展示一些后台信息给前端页面。如果需要用到消息,还需要在INSTALLED_APPS中添加django.contrib.message才能有效。如果不需要,可以把这两个都删除。
        'django.middleware.clickjacking.XFrameOptionsMiddleware',#防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
        'A_orm.middlewares.auth.AuthenticationMiddleware',
    ]
    内置中间件

    请求进来是自上而下,通过反射找到类,用for循环来执行,可以自定义中间件,但也要写入MIDDLEWAR

    1、process_request(self,request)
    #请求完执行
    
    2、process_view(self, request, callback, callback_args, callback_kwargs)
    #如果有返回值,跳转到最后一个中间件,执行最后一个中间件的response方法,逐步返回
    3、process_template_response(self,request,response)
    #默认不执行,只有在视图函数的返回对象中有render方法才会执行
    4、process_exception(self, request, exception)
    #默认啥也不执行,在视图函数出现错误是才执行,返回错误信息
    5、process_response(self, request, response)
    #响应执行
    自定义中间件
    1、做IP限制
    
    放在 中间件类的列表中,阻止某些IP访问了;
    
    2、URL访问过滤
    
    如果用户访问的是login视图(放过)
    
    如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了!
    
    3、缓存(还记得CDN吗?)
    
    客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数
    应用场景

    执行顺序:

    1.我们要在app01文件下创建一个文件(middlewares)文件,在下面创建一个.py文件写入自定义中间件

    2.在setting里面添加中间件,文件路径+功能

    3.在views.py你们调用即可.

    def index(request):
        print('1')

    7.信号

    定义:用于框架执行操作时解耦,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者

    Model signals
        pre_init                    # django的model执行其构造方法前,自动触发
        post_init                   # django的model执行其构造方法后,自动触发
        pre_save                    # django的model对象保存前,自动触发
        post_save                   # django的model对象保存后,自动触发
        pre_delete                  # django的model对象删除前,自动触发
        post_delete                 # django的model对象删除后,自动触发
        m2m_changed                 # django的model中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
        class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
    from django.db.models.signals import pre_init, post_init
    from django.db.models.signals import pre_save, post_save
    内置信号
    Management signals
        pre_migrate                 # 执行migrate命令前,自动触发
        post_migrate                # 执行migrate命令后,自动触发
    数据库迁移的时候信号
    Request/response signals
        request_started             # 请求到来前,自动触发
        request_finished            # 请求结束后,自动触发
        got_request_exception       # 请求异常后,自动触发
    from django.core.signals import request_finished
    from django.core.signals import request_started
    请求和响应的信号
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
    from django.test.signals import setting_changed
    from django.test.signals import template_rendered
    Test signals
    connection_created          # 创建数据库连接时,自动触发
    from django.db.backends.signals import connection_created
    Database Wrappers
  • 相关阅读:
    Encrypted Handshake Message
    RSAParameters Struct
    What if JWT is stolen?
    What's the difference between JWTs and Bearer Token?
    RSA Algorithm Example
    第18届Jolt大奖结果公布
    Ruby on rails开发从头来(windows)(三十六) 调试技巧
    Ruby on rails开发从头来(四十二) ActiveRecord基础(主键和ID)
    YouTube开放基础技术架构 让用户建自家YouTube
    Ruby on rails开发从头来(四十) ActiveRecord基础(Boolean属性)
  • 原文地址:https://www.cnblogs.com/tianshuai1/p/11042166.html
Copyright © 2011-2022 走看看