• forms组件和cookie和session


    一、多对多三种创建方式

    1.全自动(推荐使用*).ManyToManyField(to='Author')

    ​ 优势:不需要你手动创建第三张表

    ​ 不足:由于第三张表不是你手动创建的,也就意味着第三张表字段是固定的无法做扩展

    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)
    

    2.纯手动(了解即可)

    不依赖于ManyToMany,自己创建第三张表,里面是有ForeignKey自己做两张表的关联

    ​ 优势:第三张可以任意的扩展字段

    ​ 不足:orm查询不方便

    class Book(models.Model):
    				title = models.CharField(max_length=32)
    				price = models.DecimalField(max_digits=8,decimal_places=2)
    
    			class Author(models.Model):
    				name = models.CharField(max_length=32)
    			
    			class Book2Author(models.Model):
    				book = models.ForeignKey(to='Book')
    				author = models.ForeignKey(to='Author')
    				create_time = models.DateField(auto_now_add=True)
    

    3.半自动(推荐使用******)

    优势:结合了全自动和纯手动的两个优点

    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='Book2Author',through_fields=('book','author'))
    				# through 告诉django orm 书籍表和作者表的多对多关系是通过Book2Author来记录的
    				# through_fields 告诉django orm记录关系时用过Book2Author表中的book字段和author字段来记录的
    				"""
    				多对多字段的
    				add
    				set
    				remove
    				clear不支持
    				"""
    				
    			class Author(models.Model):
    				name = models.CharField(max_length=32)
    				# 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)
    

    二、forms组件

    forms组件三大功能:
    1.渲染前端获取用户输入的标签
    2.校验数据
    3.展示错误信息
    注意:forms组件只能渲染获取用户输入的标签 提交按钮需要用户自己写

    手动实现一个注册功能

    要求:当用户输入非法内容时,警告
    def login(request):
        error={'username':'','password':''}
        if request.method=='POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if '金梅瓶' in username:
                error['username']='含有金梅瓶等非法信息'
            if len(password) <3:
                error['password']='密码太短'
        return render(request,'login.html',locals())
    
    <form action="" method="POST">
        <p>用户名:<input type="text" name="username"><span style="color: red">{{ error.username }}</span></p>
        <p>密码:<input type="password" name="password"><span style="color: red">{{ error.password }}</span></p>
        <input type="submit">
    
    刚刚完成了3不操作:1、前端页面搭建2.将数据传输到后端做校验3.展示错误信息
    forms组件能够直接帮你完成上面的三步操作
    form组件

    Django中不同的字段没有什么约束意义,唯一的意义就是给校验性组件用的,

    Django中的测试环境:pycharm最下面一栏的“python Console”

    1.基本用法

    forms组件中所有的字段默认都是必填的(默认就是required=True)

    # 使用forms组件,首先需要导入forms模块
    from django import forms
    class LoginForm(forms.Form):# 写一个基础了forms.Form的类
        username = forms.CharField(max_length=8,min_length=3)  # 用户名最长八位最短三位
        password = forms.CharField(max_length=8,min_length=5)  # 密码最长八位最短五位
        email = forms.EmailField()  # email必须是邮箱格式
    

    2.基本使用

    关键字:

    is_valid()
    errors
    cleaned_data  
    
    from app01 import views
    # 1.将需要校验的数据 以字典的方式传递给自定义的类 实例化产生对象
    form_obj = views.LoginForm({'username':'jason','password':'123','email':'123'})
    # 2.如何查看数据是否全部合法
    form_obj.is_valid()  # 只有所有的数据都符合要求 才会是True
    False
    # 3.如何查看错误原因
    form_obj.errors
    {
        'password': ['Ensure this value has at least 5 characters (it has 3).'], 
        'email': ['Enter a valid email address.']
    }
    # 4.如何查看通过校验的数据。
    form_obj.cleaned_data  
    {'username': 'jason'}
    # 5.渲染前![](https://img2018.cnblogs.com/blog/1689626/201909/1689626-20190925171951834-595759635.png)
    端页面 先生成一个空对象 并将对象传递给前端页面
    form_obj = MyForm()
    # 注意事项:
    1.自定义类中所有的字段默认都是必须要传值的
    2.可以额外传入类中没有定义的字段名 forms组件不会去校验 也就意味着多传一点关系没有
    

    注意:所有验证通过的数据都在cleaned_data这个大字典中

    3.form组件渲染页面的三种方式

    注意事项

    ​ 1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入的标签 提交按钮需要你手动添加

    ​ 2.input框的label注释 不指定的情况下 默认用的类中字段的首字母大写,通过类中指定label参数可更改

    一、第一种渲染页面

    <p>第一种渲染页面的方式(封装程度太高 一般只用于本地测试  通常不适用)</p>
    {{ form_obj.as_p }}  
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}#写和没写一样
    
    

    二:可扩展性较高 ,若有很多input框,需要手写,书写麻烦!

    <p>第二种渲染页面的方式(可扩展性较高 书写麻烦)</p>
    # form_obj.username.label,第二个点是取input框获取input框的中英文注释!
    <p>{{ form_obj.username.label }}{{ form_obj.username }}</p>
    <p>{{ form_obj.password.label }}{{ form_obj.password }}</p>
    <p>{{ form_obj.email.label }}{{ form_obj.email }}</p>
    

    三、第三种渲染页面的方式

    <p>第三种渲染页面的方式(推荐)</p>
    {% for foo in form_obj %}
    <p>{{ foo.label }}{{ foo }}</p>
    <span>{{ foo.errors.0 }}</span># 前端展示错误信息,这里的foo相当于上面的form_obj.username、form_obj.password、form_obj.email.
    {% endfor %}
    

    3.展示错误信息

    {% for foo in form_obj %}
    <p>{{ foo.label }}:{{ foo }}
        <span>{{ foo.errors.0 }}</span>
        </p>
        {% endfor %}
    
    #后端代码:max_length,min_length,required
    password = forms.CharField(max_length=8,min_length=5,label='密码',error_messages={
            ':max_length':'密码最大八位',
            'min_length':'密码最小五位',
            'required':'密码不能为空'
        },required=False,validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')])  # 密码最长八位最短五位'
    
    # 注意:邮箱有一个invalid参数
    email = forms.EmailField(
            label='邮箱',error_messages={
                'required':'不能为空'
                ,'invalid':'邮箱格式不正确',
            }
        )
    

    展示默认值:initial

    4.钩子函数(HOOK):用来自定义校验规则
    用法:在自定义的form类中书写方法即可

    1.全局钩子 :校验用户两次密码是否一致

    # 全局钩子(针对多个字段做额外的校验)    比如校验用户两次密码是否一致
    			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
    

    2.局部钩子:针对某一个字段做额外的校验

    # 局部钩子(针对某一个字段做额外的校验)
    1.通过cleaned_data获取
    2.add_error报错
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            self.add_error('username','光喊666是不行的 你得自己上')
            return username
    
    

    5.forms组件其他字段及操作方式

    required 是否必填

    label 注释信息

    error_messages 报错信息

    initial 默认值:改的就是标签的value值

    widget 控制标签属性和样式

    widget=widgets.PasswordInput()
    控制标签属性
    widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})
    

    6.其他字段了解知识点(知道有这些对象 需要用到的时候 能够知道去哪找)

    # 单选的radio框 
    gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=2,
        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()
    )
    

    7.cookie与session

    由于http协议是无状态。cookie是保存在客户端浏览器上的,session是保存服务端上的,session是依赖于cookie的,所有的保存用户登录状态或者各种校验基本都需要依赖于cookie

    7.1django操作cookie与session

    ​ 设置cookie利用的就是HttpResponse对象(3个)

    # 设置浏览器的cookie
    obj = HttpResponse()
        obj.set_cookie('k1','v1',max_age=100)
        return obj
    # 获取浏览器的cookie
    获取cookie,获取浏览器的cookies
    request.COOKIE.get()  # request.COOKIE把它看成是一个大字典
    

    如下:

    #给浏览器设置cookie
    def lg(request):
        if request.method=='POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username =='wx' and password =='123':
                res = redirect('/home/')
                res.set_cookie('name','wx111')#给浏览器设置cookie
                return res
        return render(request,'lg.html')
    
    
    def home(request):
        if request.COOKIES.get('name'):#判断是否给浏览器设置了cookie
            return HttpResponse('登录了哦')
        return redirect('/lg/')
    

    设置登录认证装饰器,批量认证是否设置了cookie

    
    def lg(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'jason' and password == '123':
                # 先获取url中get请求携带的参数
                old_url = request.GET.get('next')
                # 判断用户是直接访问的登陆页面 还是从别的页面的调过来
                if old_url:
                    obj = redirect(old_url)
                else:
                    # 如果用户直接访问的登陆页面 那么登陆完成之后 直接跳到网站的首页
                    obj = redirect('/home/')
                obj.set_cookie('name','jason',max_age=30)  # 浏览器上就会保存键值对name:jason
                return obj
        return render(request,'lg.html')
    
    def login_auth(func):
        @wraps(func)
        def inner(request,*args,**kwargs):
            # 从request中获取cookie
            # print(request.path)
            # print(request.get_full_path())
            target_url = request.get_full_path()
            if request.COOKIES.get('name'):
                res = func(request,*args,**kwargs)
                return res
            else:
                return redirect('/lg/?next=%s'%target_url)
        return inner
    

    删除cookie
    obj1.delete_cookie("k1")

    设置超时时间
    max_age=None, 超时时间
    expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)

    obj.set_cookie('name','jason',max_age=30)  # 浏览器上就会保存键值对name:jason,并启动失效时间
    

    session

    1设置session

    request.session['name'] = 'jason'
    			"""
    			上面这一句话发生了三件事
    				1.django 内部自动生成一个随机字符串
    				2.将随机字符串和你要保存的数据 写入django_session表中(现在内存中生成一个缓存记录 等到经过中间件的时候才会执行)
    				3.将产生的随机字符串发送给浏览器写入cookie
    					sessionid:随机字符串
    服务端保存用户信息 不一定非要在django_session表中保存。可以利用其他数据库或者换成作为session的暂存地
    

    2获取session

    request.session.get('name')
    上面这一句话发生了三件事
    1.django内部会自动从请求信息中获取到随机字符串
    2.拿着随机字符串去django_session表中比对
    3.一旦对应上了就将对应的数据解析出来放到request.session中
    
    

    django session默认的超时时间是14天

    django_session表中的一条记录针对一个浏览器

    删除当前的会话数据并删除会话的Cookie。

    request.session.delete()

    将浏览器和服务端全部删除

    request.session.flush()
    这用于确保前面的会话数据不可以再次被用户的浏览器访问
    例如,django.contrib.auth.logout() 函数中就会调用它。

    # 设置会话Session和Cookie的超时时间
    		request.session.set_expiry(value)
    			* 如果value是个整数,session会在些秒数后失效。
    			* 如果value是个datatime或timedelta,session就会在这个时间后失效。
    			* 如果value是0,用户关闭浏览器session就会失效。
    			* 如果value是None,session会依赖全局session失效策略。
    

    总结:你在后期可以将一些数据保存到session表中,保存的数据 可以在后端任意位置获取到

  • 相关阅读:
    python读写操作(txt, mat, xls, etc文件)
    开发linux版QQ就是支持未来的国产操作系统
    为知笔记linux绿色版的快速调用
    数学物理中的常见误区
    markdown语法小结
    信息爆炸时代的知识获取
    matlab: 数据的读写
    APS期刊投稿准备: REVTex格式
    markdown基本语法
    常见的数学关系
  • 原文地址:https://www.cnblogs.com/ZDQ1/p/11582063.html
Copyright © 2020-2023  润新知