day59

目录

多对多三种建表方式

  1. 全自动

    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自动创建
    • 内置了add/remove/set/clear四个操作

    缺点:

    • 自动创建的第三张关系表无法扩展和修改字段,表的扩展性较差
  2. 纯手动

    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)

    优点:

    • 第三张表中所有字段都可以自己定义

    缺点:

    • 不再支持跨表查询,不再有正反向的概念
    • 没有了add/remove/set/clear四个操作
  3. 半自动

    class Book(models.Model):
     title = models.CharField(max_length=32)
     # 多对多关系字段
     authors =   models.ManyToManyField(
         to='Authors',
         through='Book2Author',
         through_fields=("book","authors")
     )
    
    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')
    
    '''
    当你的ManyToManyField只有一个参数to的情况下,orm会自动帮你创建第三张表;
    如果你加了through和through_fileds那么orm就不会自动帮你你创建,但是会在内部帮你维护关系,让你能够继续使用orm的跨表查询
    '''

    优点:

    • 可以添加修改第三张关系表中的字段
    • 支持orm跨表查询

    缺点:

    • 不支持add/remove/set/clear四个操作

FORM组件

主要功能:

  • 生成可用的HTML标签
  • 对用户提交的数据进行校验
  • 保留上次输入的内容

前提

from django import forms

#需要先定义一个类
class MyForm(forms.Form):
    
    username = forms.CharField(max_length=8,min_length=3)
    
    password = forms.CharField(max_length=8,min_length=3)
    # email字段 必须是邮箱格式
    email = forms.EmailField()

前端校验数据

# 实例化类
form_obj = views.MyForm({'username':'jason','password':'12','email':'123'})

# 查看校验的数据是否合法
form_obj.is_valid()

# 查看不符合规则的字段及错误的理由
form_obj.errors

# 查看符合规则的字段的数据
form_obj.cleaned_data

# 传值数量
'''
因为是由类的字段向实例化对象字段的映射,所以不能少传;但是多传的话,多传的字段不会进行校验
'''

渲染标签

forms组件只会帮你渲染获取用户输入的标签,不会渲染提交按钮

  1. 方式一:封装程度太高,不推荐使用,可以用在本地测试

    {{ form_obj.as_p }}  <!--自动渲染所有input框  -->
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
  2. 方式二:不推荐使用

    {{ form_obj.username.label }}{{ form_obj.username }}
    {{ form_obj.username.label }}{{ form_obj.password }}
    {{ form_obj.username.label }}{{ form_obj.email }}
  3. 方式三:推荐使用

    {% for form in form_obj %}
     <!--form 等价于你方式2中的对象点字段名-->
     <p>{{ form.label }}{{ form }}</p>  
    
    {% endfor %}

展示信息

<form action="" method="post" novalidate>
    {% for forms in form_obj %}
    <p>
        {{ forms.label }}{{ forms }}
        <span>{{ forms.errors.0 }}</span>
    </p>  <!--form 等价于你方式2中的对象点字段名-->
    {% endfor %}
    <input type="submit">
</form>

后端校验

前端校验可有可无,后端校验必不可少

<!--告诉浏览器不做前端校验-->
<form action="" method="post" novalidate>

内置校验器

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

自定义校验器

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
 
 
# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(
        r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'
    )
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')
 
 
class PublishForm(Form):
 
 
    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '标题不能为空',
                                            'min_length': '标题最少为5个字符',
                                            'max_length': '标题最多为20个字符'},
                            widget=widgets.TextInput(
                                attrs={'class': "form-control",
                                       'placeholder': '标题5-20个字符'}
                            ))
 
 
    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手机不能为空'},
                            widget=widgets.TextInput(
                                attrs={'class': "form-control",
                                       'placeholder': u'手机号码'}
                            ))
 
    email = fields.EmailField(required=False,
                            error_messages={
                                'required': u'邮箱不能为空',
                                'invalid': u'邮箱格式错误'
                            },
                            widget=widgets.TextInput(
                                attrs={'class': "form-control", 
                                       'placeholder': u'邮箱'
                                      }
                            ))

HOOK方法

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        },
        widget=forms.widgets.TextInput(attrs={"class": "form-control"})
    )
    ...
    # 定义局部钩子,用来校验username字段
    def clean_username(self):
        value = self.cleaned_data.get("username")
        if "666" in value:
            raise ValidationError("光喊666是不行的")
        else:
            return value
class LoginForm(forms.Form):
    ...
    password = forms.CharField(
        min_length=6,
        label="密码",
        widget=forms.widgets.PasswordInput(
                    attrs={'class': 'form-control'}, 
                    render_value=True)
                )
    re_password = forms.CharField(
        min_length=6,
        label="确认密码",
        widget=forms.widgets.PasswordInput(
                    attrs={'class': 'form-control'}, 
                    render_value=True)
                )
    ...
    # 定义全局的钩子,用来校验密码和确认密码字段是否相同
    def clean(self):
        password_value = self.cleaned_data.get('password')
        re_password_value = self.cleaned_data.get('re_password')
        if password_value == re_password_value:
            return self.cleaned_data
        else:
            self.add_error('re_password', '两次密码不一致')
            raise ValidationError('两次密码不一致')

常用字段和插件(了解即可)

#默认值
initial='默认值'

#重写错误信息
error_messages={
    'requeire':'不能为空',
    'invalid':'格式错误',
    'min_length':'用户名最短8位',
}

#修改标签类
widget = forms.widgets.PasswordInput(attrs={'class':'c1 c2'})

更多

上一篇:javascript-使用onclick将变量传递到表单


下一篇:php-FILTER_VALIDATE_EMAIL