Django多对多关系建立及Form组件

Django多对多关系

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)

好处:第三张表中字段个数和字段名称全都可以自己定义

不足:不再支持orm跨表查询 不再由正反向的概念

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"))
        # 不通过orm创建,而是通过第三张表中->through='Book2Author'的through_fields=("authors","book"),authors和book字段
        #     through_fields=("authors","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')
  • 不通过orm创建,而是通过第三张表中->through='Book2Author'的through_fields=("authors","book"),authors和book字段
  • through_fields=("authors","book")中的"authors"字段,可以这样记:在哪张表里面该字段就放在最前面
  • 该表可以有任意多的外键字段
  • 可以扩展任意的字段

好处:可以任意的添加和修改第三张表中的字段
并且支持orm跨表查询
不足:不支持

add
remove
set
clear

forms校验组件

forms组件
    前戏
        需求:
            1.写一个注册页面 获取用户输入的用户名和密码
            提交到后端之后 后端需要对用户名和密码做校验
            用户名里面不能含有葫芦娃
            密码不能少于三位
            如果不符合 展示对应的错误信息
            
        forms组件   能够做的事情
        1.手动书写html代码获取用户输入              >> >> >>    渲染标签
        2.将数据转递给后端做数据校验                >> >> >>    校验数据
        3.如果数据有错误 你还展示了错误信息         >> >> >>    展示信息

使用forms组件的前提是 你需要提前写一个类

from django import forms

class MyForm(forms.Form):
    # username字段 最少三位 最多八位
    username = forms.CharField(max_length=8,min_length=3)
    # password字段 最少三位  最多八位
    password = forms.CharField(max_length=8,min_length=3)
    # email字段 必须是邮箱格式
    email = forms.EmailField()
    
校验数据
    # 1.给写好的类 传字典数据(待校验的数据)
    form_obj = views.MyForm({'username':'jason','password':'12','email':'123'})
    # 2.如何查看校验的数据是否合法
    form_obj.is_valid()
    False  # 只有当你的数据全部符合校验规则的情况下 结果才是True 否则都为False
    # 3.如何查看不符合规则的字段及错误的理由
    form_obj.errors
    {
    'password': ['Ensure this value has at least 3 characters (it has 2).'],
    'email': ['Enter a valid email address.']
    }
    # 4.如何查看符合校验规则的数据
    form_obj.cleaned_data
    {'username': 'jason'}
    # 5.forms组件中 定义的字段默认都是必须传值的  不能少传
    form_obj = views.MyForm({'username':'jason','password':'12345'})
    form_obj.is_valid()
    False
    form_obj.errors
    {'email': ['This field is required.']}
    # 6.forms组件只会校验forms类中定义的字段  如果你多传了 不会有任何影响
    form_obj = views.MyForm({'username':'jason','password':'12345','email':'123@qq.com','xxx':'嘿嘿嘿'})
    form_obj.is_valid()
    True
    
渲染标签
    forms组件只会帮你渲染获取用户输入的标签 不会帮你渲染提交按钮 需要你自己手动添加

    <p>forms组件渲染标签方式1:封装程度态高 不推荐使用 但是可以用在本地测试</p>
    {{ form_obj.as_p }}  <!--自动渲染所有input框  -->
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
    <p>forms组件渲染标签方式2:不推荐使用 写起来太烦了</p>
    {{ form_obj.username.label }}{{ form_obj.username }}
    {{ form_obj.username.label }}{{ form_obj.password }}
    {{ form_obj.username.label }}{{ form_obj.email }}
    <p>forms组件渲染标签方式3:推荐使用 </p>
    {% for form in form_obj %}
    <p>{{ form.label }}{{ form }}</p>  <!--form 等价于你方式2中的对象点字段名-->
    {% endfor %}
    
展示信息
<p>forms组件渲染标签方式3:推荐使用 </p>
<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>

使用forms组件实现注册功能

先定义好一个ReGForm类:

from django import forms

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

再写一个视图函数

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

login.htmll

<!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的功能:

前端页面是form类的对象生成的——>生成HTML标签功能

当用户名和密码输入为空或输错之后 页面都会提示——>用户提交校验功能

当用户输错之后再次输入上次的内容还保留在input框中——>保留上次输入内容

form常用字段和插件

initial

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

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

error_messages

重写错误信息

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        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="密码",
        widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )

radioSelect

单radio值为字符串

class LoginForm(forms.Form):
    username = forms.CharField(
        min_length=8,
        label="用户名",
        initial="张三",
        error_messages={
            "required": "不能为空",
            "invalid": "格式错误",
            "min_length": "用户名最短8位"
        }
    )
    pwd = forms.CharField(min_length=6, label="密码")
    gender = forms.fields.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

单选select

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

多选select

class LoginForm(forms.Form):
    ...
    hobby = 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()
    )

数据校验

数据的校验通常前后端都必须有
但是前端的校验可有可无 并且弱不禁风
后端的校验必须要有 并且必须非常的全面
如何告诉浏览器不做校验 form表单中加一个novalidate参数即可

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

内置的校验器

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

钩子函数 HOOK

当你觉得上面的所有的校验还不能够满足你的需求 你可以考虑使用钩子函数
是一个函数 函数体内你可以写任意的校验代码

局部钩子

你想校验单个字段

全局钩子

你想校验多个字段

Hook函数实例

posted @ 2019-12-05 12:20  南歌先生  阅读(364)  评论(0编辑  收藏  举报