• django form组件 cookies,session


    django form组件

    1. 渲染标签  就是组件里面的字段在前端展示叫做渲染标签
    2. 校验数据  用户输入的数据提交给后端组件叫做校验数据
      1. forms组件中定义的字段都是必须传值的(required=True)
      2. lable不写默认用的是字段首字母大写
      3. 如果提交的信息不合法,input框内的数据会保留  
    3. 展示信息  校验未通过展示错误信息

    校验数据

        第一步需要一个form类

    form django import forms
    
    class MyForm(forms.Form):
        name = forms.CharField(max_length=6)
        password = forms.CharField(max_length=8,min_length=3)
        email = forms.EmailField(required=True)  #required  必选的

     不指定lable 默认会把条件首字母大写展示在前端标签渲染的时候

       第二步实例化form对象

    form_obj = MyForm({'name':'jason'})

       第三步查看数据校验是否合法

    form_obj.is_valid()        #只有当所有的字段都校验通过才会返回True

       第四步查看校验错误的信息

    form_obj.errors  #这个里面放的是所有校验未通过的字段及错误提示
    
    
                    """
                    {
                    'name': ['Ensure this value has at most 6 characters (it has 7).'], 
                    'password': ['Ensure this value has at least 3 characters (it has 2).'], 
                    'email': ['Enter a valid email address.']
                    }
    
                    """

      第五步查看校验通过的数据

    form_obj.cleaned_data    #符合校验规则数据都会被放到该对象中
    
    #ps:form组件校验数据的规则从上往下依次取值校验
        #校验通过的放到cleaned_data
        #校验失败的方法哦errors
    
    #注意:
        #form中所有的字段默认都是必须传值的(required=True)
        #校验数据的时候可以多传(多传的数据不会做任何的校验 >>>不会影响form校验规则)

    渲染标签

      form组件值帮你渲染获取用户输入的标签,不会帮你渲染提交按钮,需要手动添加

      第一种渲染方式(可扩展性较差)

    {{ form_obj.as_p }}
    
    {{ form_obj.as_ul }}

      第二种渲染方式

    <form action="">
        <p>{{ form_obj.name.label }}{{form_obj.name}}</p>
        <p>{{ form_obj.password.label }}{{ form_obj.password }}</p>
        <p>{{ form_obj.email.lable }}{{ form_obj.email }}</p>
        <input type='submit'>
    </form>

      第三种渲染标签的方式

    <form action='' method='post' >
        {% for foo in form_obj %}
            <p>
                    {{ foo.lable }}{{ foo }}
            </p>
        {% endfor %}
    </form>

      对应后端

    def reg(request):
        #生成一个空对象
        form_obj = MyForm()
    if request.method = 'POST':
            print(requets.POST)
        
            form_obj = MyForm(request.POST)
    if form_obj.is_valid():
                print(form_obj.cleaned_data)
                models.User.objects.create(**form_obj.cleaned_data)
        return render(request,'reg.html',locals())

      前端取消校验

    <form action='' method='post' novalidate>
    </form>

    form组件提交数据如果数据不合法,页面上会保留之前用户输入的信息 在使用form组件对模型表进行数据校验的时候,只需要保证字段一致 (form_obj = MyForm()   form_obj = MyForm(request.POST))  那么你在创建的对象的时候就直接**form_obj.cleaned_data

    展示校验信息

    <form action="" method="post" novalidate>
        {% for foo in form_obj %}
            <p>
                {{ foo.label }}{{ foo }}
                <span>{{ foo.errors.0 }}</span>
            </p>
        {% endfor %}
        <input type="submit">
    </form>

    普通方式手写注册功能

    # 注册
    def register(request):
        error_msg = ""
        if request.method == "POST":
            username = request.POST.get("name")
            pwd = request.POST.get("pwd")
            # 对注册信息做校验
            if len(username) < 6:
                # 用户长度小于6位
                error_msg = "用户名长度不能小于6位"
            else:
                # 将用户名和密码存到数据库
                return HttpResponse("注册成功")
        return render(request, "register.html", {"error_msg": error_msg})
    views
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册页面</title>
    </head>
    <body>
    <form action="/reg/" method="post">
        {% csrf_token %}
        <p>
            用户名:
            <input type="text" name="name">
        </p>
        <p>
            密码:
            <input type="password" name="pwd">
        </p>
        <p>
            <input type="submit" value="注册">
            <p style="color: red">{{ error_msg }}</p>
        </p>
    </form>
    </body>
    </html>
    login.html

    使用form组件实现注册功能

      注册功能

        1 渲染前端标签获取用户输入     >>>  渲染标签   就是组件里面的字段在前端展示叫做渲染标签

        2 获取用户输入传递到后端校验    >>>  校验数据   用户输入的数据提交给后端组件叫做校验数据

        3 校验未通过展示错误信息      >>>  展示信息

      校验数据(前后端都可以校验)

        校验前端后端都可以做,但是前端可以不做,后端必须得做!!!

       

      先定义好一个ReForm类:

    form django import forms
    
    #按照django form组件的要求自己写一个类
    class ReForm(forms.Form):
        name = forms.CharField(label='用户名')
        pwd = forms.CharField(lable='密码')

      再写一个视图函数:

    #使用form组件实现注册方式
    def register2(request):
        form_obj  = ReForm()
        if requetst.method = 'POST':
            #实例化form对象的时候,把post提交过来的数据直接传进去
            form_obj = ReForm(request.POST)
            #调用form_obj校验数据的方法
            if form_obj.is_vaild():
                return HttpResponse('注册成功')
        return render(request,'register2.html',local())

      login2.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册2</title>
    </head>
    <body>
        <form action="/reg2/" method="post" novalidate autocomplete="off">
            {% csrf_token %}
            <div>
                <label for="{{ form_obj.name.id_for_label }}">{{ form_obj.name.label }}</label>
                {{ form_obj.name }} {{ form_obj.name.errors.0 }}
            </div>
            <div>
                <label for="{{ form_obj.pwd.id_for_label }}">{{ form_obj.pwd.label }}</label>
                {{ form_obj.pwd }} {{ form_obj.pwd.errors.0 }}
            </div>
            <div>
                <input type="submit" class="btn btn-success" value="注册">
            </div>
        </form>
    </body>
    </html>

    常用字段与插件

    创建Form类时,主要涉及到 【字段】和【插件】,字段用户对用户请求数据的验证,插件用于自动生成HTML

    from django import forms

    form django.forms import widgets

    initial  初始值,input框里面的初始值

    class LoginForm(forms.Form):
        username = forms.CharField(
            min_length=8,
            lablel = '用户名',
            initial = '张三'   #设置默认值
    )
        pwd = forms.CharField(min_length=6,label='密码')

    error_messages  重写错误信息

    class LoginForm(form.Form):
        username = forms.CharField(
            min_length= 8,
            label = '用户名',
            inititla = '张三',
            error_messages={
                'required':'不能为空',
                'invalid':'格式错误',   #无效
                'min_length':'用户名最短8位'})
        pwd = forms.CharField(min_length=6,label='密码')

    password

    class LoginForm(forms.Form):
        pwd = forms.CharField(
            min_length=6,
            label = '密码',
            error_messages={
                'max_length':'密码最长8位',
                'required':'秘密不能为空'},
            widget = forms.widgets.PasswordInport(attrs={'class':'c1 form-control'}))    

    email

    email = forms.EmailField(error_messages={
        'invalid':'邮箱格式不正确',  #无效
         'required':'邮箱不能为空',})

    gender  readioSelect  单radio值为字符串

    gender = forms.ChoiceField(
        choices = ((1,''),(2,''),(3,'保密')),
        label = '性别',
        initial = 3,    #默认值
        widget = forms.widgets.RadioSelect())

    hobby  单选Select

        hobby = forms.ChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=3,
            widget=forms.widgets.Select()
        )

    hobby1  多选Select

     hobby1 = forms.MultipleChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=[1, 3],
            widget=forms.widgets.SelectMultiple()
        )

    单选checkbox

    class LoginForm(forms.Form):
        ...
        keep = forms.ChoiceField(
            label="是否记住密码",
            initial="checked",
            widget=forms.widgets.CheckboxInput()
        )

    多选checkbox

    class LoginForm(forms.Form):
        ...
        hobby = forms.MultipleChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=[1, 3],
            widget=forms.widgets.CheckboxSelectMultiple()
        )

    keep  登录界面是否记住密码

        keep = forms.ChoiceField(
            label="是否记住密码",
            initial="checked",
            widget=forms.widgets.CheckboxInput()
        )

    choice字段注意事项

      在使用选择标签时,需要注意choices的选项可以配置从数据库中获取,但是由于是静态字段 获取的值无法实时更新,需要重写构造方法从而实现choice实时更新。

      方式1:

    from django.forms import Form
    from django.forms import widgets
    from django.forms import fields
    
     
    class MyForm(Form):
     
        user = fields.ChoiceField(
            # choices=((1, '上海'), (2, '北京'),),
            initial=2,
            widget=widgets.Select
        )
     
        def __init__(self, *args, **kwargs):
            super(MyForm,self).__init__(*args, **kwargs)
            # self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
            #
            self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')

      方式2:

    from django import forms
    from django.forms import fields
    from django.forms import models as form_model
    
     
    class FInfo(forms.Form):
        authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())  # 多选
        # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())  # 单选

    Django Form所有内置字段

    Field
        required=True,               是否允许为空
        widget=None,                 HTML插件
        label=None,                  用于生成Label标签或显示内容
        initial=None,                初始值
        help_text='',                帮助信息(在标签旁边显示)
        error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
        validators=[],               自定义验证规则
        localize=False,              是否支持本地化
        disabled=False,              是否可以编辑
        label_suffix=None            Label内容后缀
     
     
    CharField(Field)
        max_length=None,             最大长度
        min_length=None,             最小长度
        strip=True                   是否移除用户输入空白
     
    IntegerField(Field)
        max_value=None,              最大值
        min_value=None,              最小值
     
    FloatField(IntegerField)
        ...
     
    DecimalField(IntegerField)
        max_value=None,              最大值
        min_value=None,              最小值
        max_digits=None,             总长度
        decimal_places=None,         小数位长度
     
    BaseTemporalField(Field)
        input_formats=None          时间格式化   
     
    DateField(BaseTemporalField)    格式:2015-09-01
    TimeField(BaseTemporalField)    格式:11:12
    DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
     
    DurationField(Field)            时间间隔:%d %H:%M:%S.%f
        ...
     
    RegexField(CharField)
        regex,                      自定制正则表达式
        max_length=None,            最大长度
        min_length=None,            最小长度
        error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
     
    EmailField(CharField)      
        ...
     
    FileField(Field)
        allow_empty_file=False     是否允许空文件
     
    ImageField(FileField)      
        ...
        注:需要PIL模块,pip3 install Pillow
        以上两个字典使用时,需要注意两点:
            - form表单中 enctype="multipart/form-data"
            - view函数中 obj = MyForm(request.POST, request.FILES)
     
    URLField(Field)
        ...
     
     
    BooleanField(Field)  
        ...
     
    NullBooleanField(BooleanField)
        ...
     
    ChoiceField(Field)
        ...
        choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
        required=True,             是否必填
        widget=None,               插件,默认select插件
        label=None,                Label内容
        initial=None,              初始值
        help_text='',              帮助提示
     
     
    ModelChoiceField(ChoiceField)
        ...                        django.forms.models.ModelChoiceField
        queryset,                  # 查询数据库中的数据
        empty_label="---------",   # 默认空显示内容
        to_field_name=None,        # HTML中value的值对应的字段
        limit_choices_to=None      # ModelForm中对queryset二次筛选
         
    ModelMultipleChoiceField(ModelChoiceField)
        ...                        django.forms.models.ModelMultipleChoiceField
     
     
         
    TypedChoiceField(ChoiceField)
        coerce = lambda val: val   对选中的值进行一次转换
        empty_value= ''            空值的默认值
     
    MultipleChoiceField(ChoiceField)
        ...
     
    TypedMultipleChoiceField(MultipleChoiceField)
        coerce = lambda val: val   对选中的每一个值进行一次转换
        empty_value= ''            空值的默认值
     
    ComboField(Field)
        fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                                   fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
     
    MultiValueField(Field)
        PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
     
    SplitDateTimeField(MultiValueField)
        input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
        input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
     
    FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
        path,                      文件夹路径
        match=None,                正则匹配
        recursive=False,           递归下面的文件夹
        allow_files=True,          允许文件
        allow_folders=False,       允许文件夹
        required=True,
        widget=None,
        label=None,
        initial=None,
        help_text=''
     
    GenericIPAddressField
        protocol='both',           both,ipv4,ipv6支持的IP格式
        unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
     
    SlugField(CharField)           数字,字母,下划线,减号(连字符)
        ...
     
    UUIDField(CharField)           uuid类型
    
    
    Django Form内置字段
    django Form内置字段

    钩子函数

    局部钩子  (单个字段的校验利用局部钩子函数)

    def clean_name(self):
        name = self.cleaned_data.get('name')
        if '666' in name:
            self.add_error('name','光喊666是不行的,要有真实力!')   #自定义异常
        return name    #考虑兼容性 加上return name

       第二种主动抛出异常

        raise ValidationError('光喊666是不行的')

    全局钩子函数  (多个字段的校验利用那个全局钩子函数)

    def clean(self):
        password = self.cleaned_data.get('password')
        confrim_password = self.cleaned_data.get('confirm_password')
        if not password == confirm_password:
            self.add_error('confirm_password','两次密码不一致')
        return self.cleaned_data

    cookies session

    http协议四大特性

      1 基于TCP/IP作用于应用层的协议

      2 基于请求响应

      3 无状态

      4 无连接

    cookies   保存在客户端浏览器上的键值对

    session  保存在服务端上的键值对  服务端产生随机的串儿返回给客户端,服务端找一个地方将串儿与对应的信息存起来{'随机字符串':'敏感信息'}

    设置Cookies

    obj = HttpResponse()
    return obj
    
    obj = render()
    return obj
    
    obj = redirect()
    return obj
    
    
    
    #设置cookies
    obj.set_cookie()    #给浏览器设置cookie

       

    获取cookies

    request.COOKIES.get('name')
    request.COOKIES['name']

    推演过程

    from django import forms
    from django.forms import widgets
    
    class MyForm(forms.Form):
        name = forms.CharField(max_length=6,label='用户名',error_messages={
            'max_length':'用户名最长6位',
            'required':'用户名不能为空'  #必选的
        })
        password = forms.CharField(max_length=8,min_length=3,error_messages={
            'max_length':'密码最长为8位',
            'required':'密码不能为空',
            'min_length':'密码最少为3为'
        },widget=forms.PasswordInput(attrs={'class':'form-control'}))
        confirm_password = forms.CharField(max_length=8,min_length=3,error_messages={
            'max_length':'确认密码最大为8位',
            'min_length':'确认密码最少为3位',
            'required':'确认密码不能为空'
        },widget=forms.PasswordInput(attrs={'class':'form-control'}))
        email  = forms.EmailField(error_messages={
            'invalid':'邮箱无效',
            'required':'邮箱不能为空'
        })
    
        def clean_name(self):
            name = self.cleaned_data.get('name')
            if '666' in name:
                self.add_error('name','光靠嘴有毛用')
            return name
    
        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','两次密码不一致')
            return self.cleaned_data
    
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'jason' and password == '123':
                obj = redirect('/home/')
                obj.set_cookie('name','jason',expires=5)
                return obj
        return render(request,'login.html')
    
    
    from functools import wraps
    def login_auth(func):
        @wraps(func)
        def inner(request,*args,**kwargs):
            if request.COOKIES.get('name'):
                return func(request,*args,**kwargs)
            return redirect('/login/')
        return inner
    
    
    @login_auth
    def home(request):
        return HttpResponse('我是home页面,只有登录了才能看到')
    views
    <!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.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    
    <form action="" method="post">
        <p>username:<input type="text" name="username"></p>
        <p>password:<input type="text" name="password"></p>
        <input type="submit">
    </form>
    
    </body>
    </html>
    前端

    cookies 登录  登录验证(为了用户体验更好一点 用户没登录前点击其他链接先跳转登录 在登陆完之后再发返回之前点击的连接页面)

    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'jason' and password == '123':
          #之前判断成功之后 要么重定向 要么返回httpressponse 现在在重定向前面加了一个限制条件 重定向是原未登录时的后缀 old_path
    = request.GET.get('next') if old_path: obj = redirect(old_path) else: obj = redirect('/home/') #用户登录成功 想浏览器设置一个cookie obj.set_cookie('name','jason',expires=7*24*3600) #seeeion过期时间 max_age 也是设置超时时间的 但是不兼容ie return obj return render(request,'login.html') #装饰器 from functools import wraps def login_auth(func): @wrap(func) def inner(request,*args,**kwargs): #校验cookie #print(request.get_full_path()) 只有路径后缀 get_path 全路径 old_path = request.get_full_path() if request.COOKIES.get('name') return func(request,*args,**kwargs) return redirect('/login/?next=%s'%old_path) return inner

    删除用户浏览器上之前设置的usercookie值

    @login_auth
    def logout(request):
        rep = redirect('/login/')
        rep.delete_cookie('name')
        return rep

    设置session

    request.session['name'] = 'jason'

      当你没有创建django需要的默认表的情况下会报错no such tabel:django_session

      

      完成三件事

        1 先生成一个随机的字符串

        2 在django_session 中存储该随机字符串与数据的记录   后面有一个session存活时间是两周(14天)默认

        3 将随机的字符串发送给客户端浏览器

    获取session

    request.session.get('name')

      完成三件事

        1 django自动获取浏览器随机字符串去django_session表里面比对

        2 如果比对成功 会将当前随机字符串对应的数据赋值给request.session

        3 通过request.session操作该数据(数据不存在也不会影响我们的业务逻辑  因为get取值)

    浏览器会设置一个键为sessionid来存放session值

    删除当前会话的所有Session数据

    request.session.delete()

    删除当前的会话数据并删除会话的cooike

    request.session.flush()

      这用于确保前面的会话数据不可以再次被用户的浏览器访问

    设置会话session和cookies的超时时间

    request.session.set_expriy(value)
        #如果value是个整数,session 会在些秒数后失效,
        #如果vlaue是个datatime或timedelta,session就会在这个时间后失效。
        #如果value是0,用户关闭浏览器session就会失效。
        #如果value是None,session会依赖全局session失效策略。

     

    djnago默认的session存活时间是两周(14天)

  • 相关阅读:
    nginx.conf nginx反向代理配置文件
    linux shell date的用法
    shell find 命令 find命令报错 find: paths must precede expression:
    nginx平滑升级
    centos 6/7 tar包安装mysql 5.7
    3. Longest Substring Without Repeating Characters
    模板之类模板2
    排序之归并排序
    排序之堆排序
    排序之选择排序
  • 原文地址:https://www.cnblogs.com/lakei/p/11042124.html
Copyright © 2020-2023  润新知