zoukankan      html  css  js  c++  java
  • forms组件

    多对多的三种创建方式

      1.全自动(推荐使用*)

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

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

    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.纯手动

      自己创建第三张表
      优势:第三张可以任意的扩展字段
      不足: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
        set0
        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组件

    自己手动实现一个注册功能
    当用户的用户名包含evil   提示不符合社会主义核心价值观
    当用户的密码短于3位        提示密码太短了 不符合要求

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    </head>
    <body>
    <form action="" method="post">
        <p>username:
            <input type="text" name="username">
            <span style="color: red">{{ errors.username }}</span>
        </p>
        <p>password:
            <input type="password" name="password">
            <span style="color: red">{{ errors.password }}</span>
        </p>
        <input type="submit">
    </form>
    </body>
    </html>
    前端
    def login(request):
        errors = {'username':'','password':''}
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if 'evil' in username:
                errors['username'] = 'nono'
            if len(password) < 3:
                errors['password'] = 'nonono'
        return render(request,'login.html',locals())
    后端

    1.前端页面搭建 >>> 渲染页面
    2.将数据传输到后端做校验 >>> 校验数据
    3.展示错误信息 >>> 展示信息

    forms组件能够直接帮你完成上面的三步操作
      1.渲染前端页面
      2.校验数据是否合法
      3.展示错误信息

    1.forms组件基本用法

      1.写一个继承了forms.Form的类 

    from django import forms
    
    class LoginForm(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.基本使用

    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'}

    注意事项:
    1.自定义类中所有的字段默认都是必须要传值的
    2.可以额外传入类中没有定义的字段名 forms组件不会去校验 也就意味着多传一点关系没有

    form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com'})
    form_obj.is_valid()
    True
                        
    form_obj = views.LoginForm({'username':'jason','password':'123456'})
    form_obj.is_valid()
    False
                        
    form_obj = views.LoginForm({'username':'jason','password':'123456','email':'123@qq.com','hobby':'read'})
    form_obj.is_valid()
    True

    2.渲染页面

    三种方式
    <p>第一种渲染页面的方式(封装程度太高 一般只用于本地测试  通常不适用)</p>
    {{ form_obj.as_p }}  
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
                    
    <p>第二种渲染页面的方式(可扩展性较高 书写麻烦)</p>
    <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>
    {% endfor %}

    注意事项
    1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入的标签 提交按钮需要你手动添加
    2.input框的label注释 不指定的情况下 默认用的类中字段的首字母大写

    校验数据的时候可以前后端都校验 做一个双重的校验
    但是前端的校验可有可无 而后端的校验则必须要有,因为前端的校验可以通过爬虫直接避开
    前端取消浏览器校验功能
      form标签指定novalidate属性即可
        <form action="" method='post' novalidate></form>

    3.展示错误信息

    {% for foo in form_obj %}
        <p>{{ foo.label }}:{{ foo }}
        <span>{{ foo.errors.0 }}</span>
        </p>
    {% endfor %}
                
    前端
    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开头')])  
    后端代码

    4.钩子函数(HOOK)

    forms组件暴露给用户 可以自定义的校验规则

    局部钩子

    用法:在自定义的form类中书写方法即可

    # 局部钩子(针对某一个字段做额外的校验)   校验用户名中不能包含666 一旦包含 提示

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            self.add_error('username','光喊666是不行的 你得自己上')
        return username

    # 全局钩子(针对多个字段做额外的校验)    校验用户两次密码是否一致

    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

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

      required  是否必填

      label 注释信息

      error_messages 报错信息
      
    initial 默认值

      widget 控制标签属性和样式

    from django.forms import widgets
    widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2','username':'jason'})

      单选框的radio框

    gender = forms.ChoiceField(
        choices=((1, ""), (2, ""), (3, "保密")),
        label="性别",
        initial=3,
        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()
                    )    

    cookie与session

      由于HTTP协议是无状态的  无法记录用户状态

      cookie就是保存在客户端浏览器上的键值对

        工作原理:当你登陆成功之后  浏览器上会保存一些信息

        下次再访问的时候  就会带着这些信息去访问服务端   服务端通过这些信息来识别出你的身份

        

        cookie虽然是写在客户端浏览器上的   但是是服务端设置的

        浏览器可以选择不服从命令  禁止写cookie

      session就是保存在服务器上的键值对

        session虽然是保存在服务器上的键值对

        但是它依赖于cookie工作的

        

        服务端返回给浏览器一个随机的字符串

        浏览器以键值对的形式保存

        sessionid:随机字符串

        

        浏览器在访问服务端的时候  就会将随机字符串携带上

        后端获取随机字符串与后端的记录作比对

          随机字符串1:数据1

          随机字符串2:数据2

    如何操作Cookie
      django返回给客户端浏览器的都必须是HttpResponse对象

    return HttpResponse()
    return render()
    return redirect()
            
            
    obj1 = HttpResponse()
    return obj1
    obj2 = render()
    return obj2
    obj3 = redirect()
    return obj3

    设置cookie利用的就是HttpResponse对象
    obj1.set_cookie('k1','v1')

    获取cookie
    request.COOKIE.get()

    删除cookie
    obj1.delete_cookie("k1")

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

    登陆功能示例

    def lg(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'yzy' and password == '123':
                old_url = request.GET.get('next')
                if old_url:
                    obj = redirect(old_url)
                else:
                    obj = redirect('/home')
                obj.set_cookie('name','yzy')
                return obj
    
        return render(request,'lg.html')
    
    
    from functools import wraps
    def login_auth(func):
        @wraps(func)
        def inner(request,*args,**kwargs):
            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
    
    @login_auth
    def home(request):
        return HttpResponse('home')
    
    @login_auth
    def index(request):
        return HttpResponse('index')
    
    @login_auth
    def xx(request):
        return HttpResponse('xx')
    
    def logout(request):
        obj = redirect('/lg')
        obj.delete_cookie('name')
        return obj

    session

      设置session

    request.session['name'] = 'jason'
    """
    上面这一句话发生了三件事
        1.django 内部自动生成一个随机字符串
        2.将随机字符串和你要保存的数据 写入django_session表中(现在内存中生成一个缓存记录 等到经过中间件的时候才会执行)
        3.将产生的随机字符串发送给浏览器写入cookie
            sessionid:随机字符串
                """

      获取session

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

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

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

    # 删除当前会话的所有Session数据
    request.session.delete()  # 删除的是浏览器的sessionid信息
              
    # 删除当前的会话数据并删除会话的Cookie。
    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表中,保存的数据 可以在后端任意位置获取到

  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/KrisYzy/p/11580546.html
Copyright © 2011-2022 走看看