zoukankan      html  css  js  c++  java
  • 半自动创建多对多关系表, forms组件

    表的多对多关系的三种创建方式

    查阅框架文档及百度案例:

    基于人家已经写好的功能修改

    1. 先看配置参数
    2. 前期就是猜, 改几个参数看结果, 看猜的是否对
    3. 整体修改

    全自动创建

    class Books(models.Model):
        title = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Authors')
    
    
    class Authors(models.Model):
        name = models.CharField(max_length=32)
    

    优点: 1. 不需要手动操作关系表, 全部由orm自动创建; 2. 并且内置了四个操作关系表的方法(add, remove, set, clear)

    缺点: 自动创建的关系表无法扩展和修改字段

    纯手撸(了解)

    class Books(models.Model):
        title = models.CharField(max_length=32)
    
    
    class Authors(models.Model):
        name = models.CharField(max_length=32)
    
    
    class BooksToAuthors(models.Model):
        book = models.ForeignKey(to='Books')
        author = models.ForeignKey(to='Authors')
        create_time = models.DateField(auto_created=True)  # 关系表中的扩展字段
    

    优点: 关系表中的字段可以自己定义

    缺点: 不再支持orm跨表查询以及四个操作关系表的方法(add, remove, set, clear)

    半自动(推荐使用)

    class Books(models.Model):
        title = models.CharField(max_length=32)
    
        '''
        1. 添加through和through_field参数, ManyToManyField就不会再自动创建关系表
        2. through设置关系表通过自定义表建立, 
        3. through_fields设置通过自定义表中的哪两个字段建立多对多关系
        4. 在哪张表中声明, 该表在自定义表中对应的字段就放在前面
        '''
        authors = models.ManyToManyField(to='Authors', through='BooksToAuthors', through_fields=('book', 'author'))
    
    
    class Authors(models.Model):
        name = models.CharField(max_length=32)
        # books = models.ManyToManyField(to='Books', through='BooksToAuthors', through_fields=('author', 'book'))
    
    
    class BooksToAuthors(models.Model):
        book = models.ForeignKey(to='Books')
        author = models.ForeignKey(to='Authors')
        create_time = models.DateField(auto_created=True)  # 关系表中的扩展字段
    

    优点: 可以添加和修改关系表中的字段, 并且支持跨表查询

    缺点: 不支持四个操作关系表的方法(add, remove, clear, set)

    forms组件简介

    forms组件的作用

    1. 渲染标签--- 手动书写html代码获取用户输入
    2. 校验数据---将数据传递给后端做数据校验
    3. 展示信息---如果数据有错误, 展示错误信息
    # 简易注册信息校验示例
    def register(request):
        errors_dic = {'username': '', 'password': ''}
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if 'jinpingmei' in username:
                errors_dic['username'] = '不符合社会主义核心价值观'
            if len(password) <= 3:
                errors_dic['password'] = '密码不能少于4位'
    
        return render(request, 'register.html', locals())
    
    
    '''
    <form action="" method="post">
        <p>
            username: <input type="text" name="username">
            <span style="color: red;">{{ errors_dic.username }}</span>
        </p>
        <p>
            password: <input type="text" name="password">
            <span style="color: red;">{{ errors_dic.password }}</span>
        </p>
        <input type="submit">
    </form>
    '''
    

    forms组件校验数据

    • 使用forms组件, 先导入模块: from django import forms

    • 在views.py中自定义MyForm类

      class MyForm(forms.Form):
          username = forms.CharField(max_length=8, min_length=3)  # username字段最多8位, 最少3位
          password = forms.CharField(max_length=8, min_length=3)
          email = forms.EmailField()  # email字段必须是邮箱格式
      
    • 测试代码的第二种方式: Python Console-->Django Console

      from app01 import views
      
      form_obj = views.MyForm({'username': 'jason', 'password': '12', 'email': '456'})  # 实例化时参数为字典形式
      form_obj.is_valid()  # False, 所有数据全部符合校验规则才为True
      form_obj.errors  # {'password': ..., 'email': ['Enter a valid email address.']}, 查看不符合规则的字段及错误信息
      form_obj.cleaned_data  # {'username': 'jason'}, 查看符合校验规则的数据
      
      '''
      1. forms组件的类中定义的字段默认都必须传值, 不能少传
      2. forms组件只会校验类中定义的字段, 如果传入其他字段, 不会有任何影响
      '''
      

    forms组件渲染标签

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

    def index(request):
        # 渲染标签, 需先生成一个空的MyForm类的对象
        form_obj = MyForm()
        return render(request, 'index.html', locals())
    

    forms组件渲染标签方式一

    封装程度高, 难扩展, 只用于本地测试

    '''
    {{ form_obj.as_p }}  # 会自动渲染input框和label标签, 由p标签包裹
    {{ form_obj.as_ul }}  # ..., 由ul标签包裹
    {{ form_obj.as_table }}  # ..., 渲染到一行上
    '''
    

    forms组件渲染标签方式二

    组合: form_field_obj为form_obj的属性

    class MyForm(forms.Form):
        username = forms.CharField(max_length=8, min_length=3, label='用户名') 
        password = forms.CharField(max_length=8, min_length=3, label='密码')
        email = forms.EmailField(label='邮箱')  
    '''
    {% for form_field_obj in form_obj %}
        <p>{{ form_field_obj.label }}{{ form_field_obj }}</p>
    {% endfor %}
    '''
    

    form组件展示信息

    数据的校验通常情况前后端都有, 但前端的校验弱不禁风, 所以后端的校验必须要有, 且需非常全面

    浏览器识别到使用forms组件时会自动使用前端的校验功能

    def index(request):
        # 渲染标签, 需先生成一个空的MyForm类的对象
        form_obj = MyForm()
    
        if request.method == 'POST':  # 前端识别到后端使用forms组件时会自动先进行一轮校验
            form_obj = MyForm(request.POST)
            if form_obj.is_valid():
                return HttpResponse('数据全部OK')
            else:
                print(form_obj.errors)
        return render(request, 'index.html', locals())
    

    设置前端不做校验: <form action="" method="post" novalidate>

    def index(request):
        # 渲染标签, 需先生成一个空的MyForm类的对象
        form_obj = MyForm()  # 空对象渲染输入框
    
        if request.method == 'POST':
            form_obj = MyForm(request.POST)  # form_obj实际渲染用户数据, 两个对象的名称需一致
            if form_obj.is_valid():
                return HttpResponse('数据全部OK')
            
        return render(request, 'index.html', locals())
    
    
    '''
    <form action="" method="post" novalidate>
        {% for form_field_obj in form_obj %}
            <p> 
                {{ form_field_obj.label }}{{ form_field_obj }}  # label默认获取到的是类中字段名的首字母大写形式
                <span>{{ form_field_obj.errors.0}}</span>  # 前端获取报错信息固定写法
            </p>
    
        {% endfor %}
        <input type="submit">
    </form>
    '''
    
    
    class MyForm(forms.Form):
        username = forms.CharField(
            max_length=8,
            min_length=3,
            label='用户名',
            error_messages={  # 自定义显示报错信息
                'max_length': '用户名最长八位',
                'min_length': '用户名最短3位',
                'required': '用户名不能为空'
            }
        )
        ...
        email = forms.EmailField(
            label='邮箱',
            error_messages={
                'required': '邮箱不能为空',
                'invalid': '邮箱格式错误'
            }
        )
    

    forms组件自定义校验

    正则校验

    '''
    from django.core.validators import RegexValidator
    
    
    class MyForm(forms.Form):
        username = forms.CharField(
            ...
            ...
            validators=[
                RegexValidator(r'[0-9]+$', '请输入数字!'),  # 第一个参数为正则表达式, 第二个参数为校验不通过时的报错信息
                RegexValidator(r'^159[0-9]+$', '数字必须以159开头!'),
            ]
        )
    '''
    

    钩子函数

    书写代码校验字段输入是否合法, 在其他校验合法之后再进行钩子函数代码校验

    局部钩子: 校验单个字段

    '''
    class MyForm(forms.Form):
        ...
    
        # 校验用户名中不能含有666
        def clean_username(self):
            username = self.cleaned_data.get('username')
            if '666' in username:
                self.add_error('username', '光喊666是不行的')
    
            return username  
    '''
    

    全局钩子: 校验多个字段

    '''
    class MyForm(forms.Form):
        ...  
    
        # 校验两次输入密码是否一致
        def clean(self):
            password = self.cleaned_data.get('password')
            confirm_password = self.cleaned_data.get('confirm_password')
            if not confirm_password == password:
                self.add_error('confirm_password', '两次密码不一致!')
    
            return self.cleaned_data
    '''
    

    其他字段及参数

    需要掌握

    '''
    class MyForm(forms.Form):
        username = forms.CharField(
            ...,
            label='用户名',  # input框对应的提示信息
            initial='jason',  # 初始值
            required=False,  # 允许字段值为空
            widget=forms.widgets.PasswordInput(attrs={'class': 'form-control c1', 'pwd': '123'}),  # 密文展示, 给input框设置样式及属性
            ...
        )
    
    # 前端对应标签: <input type="password" ... class="form-control c1" pwd="123" ...>
    '''
    

    了解, 会copy即可

    '''
    radioSelect:
        gender = forms.fields.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框, 无需下拉
    	hobby = 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
    	hobby = forms.MultipleChoiceField(
            choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
            label="爱好",
            initial=[1, 3],
            widget=forms.widgets.CheckboxSelectMultiple()
        )
    '''
    
  • 相关阅读:
    计算机图形学和OpenGL(二)坐标系和绘制点线函数
    计算机图形学和OpenGL(一)OpenGL初步
    C++ 实现链表常用功能
    Cocos2d-x环境搭建
    2014年学习计划
    2013年终总结
    AS3开发必须掌握的内容
    starling性能优化
    后补个2012年的总结吧
    原生javascript实现图片懒加载
  • 原文地址:https://www.cnblogs.com/-406454833/p/12011928.html
Copyright © 2011-2022 走看看