zoukankan      html  css  js  c++  java
  • Django(九)

    Django(九)---多对多的创建方式,form组件

    多对多表创建方式

    全自动

    通过Django中的orm,只要定义好表类,orm就对自动创建多对多的表关系,自动建立第三张表,并且还可以通过add remove set clear对第三张表进行操作

    缺点:

    ​ 因为第三张表是自动创建的,所以该表无法扩展和自定义字段,标的扩展性较差

    class Book(models.Model):
        title = models.CharField(max_length=32)
        # 多对多关系字段
        authors = models.ManyToManyField(to='Authors')
        
    class Authors(models.Model):
        name = models.CharField(max_length=32)
    

    纯手写

    通过模型表类,手动创建第三张关系表

    通过手动建立第三张关系表,该表中的字段个数和字段名称都可以实现自定义

    缺点:

    ​ 自定义的第三张表,不能支持orm的跨表查询,也没有正反查询的概念

    class Book(models.Model):
        title = models.CharField(max_length=32)
        
    class Authors(models.Model):
        name = models.CharField(max_length=32)
    
    class Book2Authors(models.Model):
        book = models.ForeignKey(to="Book")
        author = models.ForeignKey(to="Authors")
        create_time = models.DateField(auto_now_add = True)
    

    半自动

    在全自动的基础上,手动创建第三张表,并在MangyToManyField方法内再加一些参数(through='手动创建的第三张表名',through_fields=('外键字段1','外键字段2')

    ​ '外键字段1'当前所在表的外键

    ​ '外键字段2'关联表的外键

    通过该方式创建第三张表,可以自定义添加任意字段,并且支持orm查询

    缺点:

    ​ 不支持 add remove set clear方法,对第三张表进行操作

    class Book(models.Model):
        title = models.CharField(max_length=32)
        # 多对多关系字段
        authors = models.ManyToManyField(to='Authors',through='Book2Author',through_fields=("book","authors"))
        """
        当你的ManyToManyField只有一个参数to的情况下 orm会自动帮你创建第三张表
        如果你加了through和through_fields那么orm就不会自动帮你创建第三张表 但是它会在内部帮你维护关系 让你能够继续使用orm的跨表查询
        through  自己指定第三张关系表
        through_fields  自己指定第三张关系表中 到底哪两个字段维护者表与表之间的多对多关系
        """
    
    class Authors(models.Model):
        name = models.CharField(max_length=32)
        # 多对多关系字段  等价
        books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=("authors","book"))
    
    class Book2Author(models.Model):
        book = models.ForeignKey(to='Book')
        authors = models.ForeignKey(to='Authors')
        
        # 该表中可以由任意多的外键字段
        # 可以扩展任意的字段
    

    form组件

    通过form组件,对用户输入的信息进行校验

    如:

    1. 用户名规定不能含有敏感词
    2. 密码不能少于3位
    def register(request):
        errors = {'username':'','password':''}
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if '哈哈' in username:
                errors['username'] = '用户名包含敏感词'
            if len(password)<4:
                errors['password'] = '密码不能少于三个'
    
        return render(request,'register.html',locals())
    
    <form action="" method="post">
        <p>username:
            <input type="text" name="username">
            <span style="color: red">{{ errors.username }}</span>
        </p>
        <p>password:
            <input type="text" name="password">
            <span style="color: red">{{ errors.password }}</span>
        </p>
        <input type="submit">
        <p></p>
    </form>
    

    校验数据

    使用form组件时,需要提前定义一个类

    from django import forms
    
    class MyForm(forms.Form):
        username = forms.CharField(max_length=8,min_length=3)
        # 使用CharField字段,max_length表示最多位数,min_length表示最少位数
        password = forms.IntegerField(max_value=8,min_value=3)
        # email字段 必须是邮箱格式
        email = forms.EmailField()
    

    通过 form_obj.is_valid()方法,可以校验提交的数据是否符合条件

    ​ 只有当数据全部符合校验规则的情况下,结果才是True

    通过 form_obj.errors方法,可以获取不符合规则的字段及错误的理由

    通过 form_obj.cleaned方法,可以获取校验通过的数据,返回的是一个字典

    forms组件中定义的字段默认都是必须传值的,不能少传,如果少传会报错

    forms组件只会校验forms类中定义的字段,如果多传了,不会有任何影响

    渲染标签

    <p>方式一:速度快,但是封装成程度太高,不能加标签样式</p>
    {{ form_obj.as_p }}
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
    
    <p>方式二:</p> #方式二写法过于繁琐
    {{ form_obj.username.label }}{{ form_obj.username }}
    {{ form_obj.password.label }}{{ form_obj.password }}
    {{ form_obj.email.label }}{{ form_obj.email }}
    
    <p>方式三:</p>  #使用该方法,不管有多少个输入框,都可以通过for循环一次性渲染
    {% for form in form_obj %}
        <p>{{ form.label }}{{ form }}</p>#和方式2中的对象点字段名一样
    {% endfor %}
    

    通过在自定义的MyForm中的属性值设置label的值,可以自定义前端label的是值

    通过设置widget=forms.widgets.TextInput({'class':'form-control',键值对})的值,可以对标签进行js渲染

    展示信息

    使用form组件,前端会自动识别,并帮你做校验

    但是前端的校验保护措施过于薄弱,因此在写项目时,需要取消前端的校验

    在后端进行真正的校验

    让浏览器不做校验,需要在form表单中添加一个novalidate参数

    <form action="" method="post" novalidate>

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

    通过{{ form.errors.0 }}可以获取后端传过来的报错信息,报错信息为英文

    在后端自定义的MyForm类中,给属性值自定义error_messages值,可是是前端得到自定义的报错信息

    username = forms.CharField(max_length=8,min_length=3,label='用户名',initial='默认值',
                               error_messages={
                                   'max_length':'用户名最长八位',
                                   'min_length':'用户名最短三位',
                                   'required':'用户名不能为空'
                               },required=False,
                               widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'})
                               )
    

    内置的校验器

    通过validators设置校验规则,规则一般为正则表达式

    from django.core.validators import RegexValidator
    validators=[
                RegexValidator(r'^[0-9]+$', '请输入数字'),
                RegexValidator(r'^159[0-9]+$', '数字必须以159开头'),
            ]
    

    勾子函数

    符合所有字段规则的数据,才会进行勾子函数内的校验

    form组件校验通过的数据会存放在cleaned_data中

    局部钩子

    # 校验用户名中不能含有666     局部钩子
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 给username所对应的框展示错误信息
            # self.add_error('username','光喊666是不行的')
            raise ValidationError('到底对不对啊')
        # 将username数据返回
        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
    

    补充知识点

    在自定义类的实行中设置 initial 值,会在前端中显示初始值

    设置required 属性,默认为True,为True时该输入框不能为空,设置为False,可以为空

    label       input对应的提示信息
    initial     input框默认值
    required  	默认为True控制字段是否必填
    widget      给input框设置样式及属性
    			widget=forms.widgets.PasswordInput({'class':'form-control c1 c2',})
                widget=forms.widgets.TextInput({'class':'form-control c1 c2',})
                widget=forms.widgets.TextInput(attrs={'class':'form-control c1 c2',})
    
  • 相关阅读:
    组合和封装
    面向对象之继承与派生
    实例化产生对象和绑定关系
    面向对象程序设计和类
    常用模块(hashlib、suprocess、configparser)
    常用模块re模块(正则表达式)
    包及常用模块(time、datetime、random、sys)
    python内置函数大全
    软件开发规范及常用模块
    [NOI Online 提高组]序列 (并查集+二分图判定)
  • 原文地址:https://www.cnblogs.com/samoo/p/11979498.html
Copyright © 2011-2022 走看看