一、多对多三种创建方式

(一)全自动

  1. ORM自动创建第三张表,不用对第三张表进行操作,内置了四个方法(add、remove、set、clear)
  2. 可扩展性差,第三张表无法扩展或修改字段
from django.db import models
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)

(二)纯手撸(基本不用)

  1. 第三张表的字段个数和字段名称全部可以自己定义
  2. 不再支持ORM跨表查询和四个内置方法(add、set、remove、clear)
from django.db import models
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)

(三)半自动(推荐使用)

  1. through:自定义指定第三张关系表
  2. through_fields:元组形式自定义指定第三张表中的关联字段(顺序和表有关,哪个表创建的,哪个字段放前面)
  3. 可以任意添加和修改地第三张表中字段
  4. 支持ORM跨表查询,不支持四种内置方法(add、set、remove、clear)
from django.db import models
class Book(models.Model):
    title = models.CharField(max_length=32)

    # 多对多关系字段
    authors = models.ManyToManyField(to='Authors',through='Book2Authors',through_fields=('book','authors'))

class Authors(models.Model):
    name = models.CharField(max_length=32)
    # books = models.ManyToManyField(to='Book',through='Book2Authors',through_fields=('authors','book'))

class Book2Authors(models.Model):
    book = models.ForeignKey(to='Book')
    authors = models.ForeignKey(to='Authors')

二、forms组件

需要导入froms:from django import forms

(一)校验数据

(1)常用内置字段及参数

所有字段默认继承Field,即Field中的参数都可以使用

  • Field

    1. required=True:是否允许为空
    2. label:label标签内显示的内容,默认首字母大写的字段名
    3. initial:初始值
    4. error_messages:设置错误信息,格式{‘参数名’:‘错误信息’},比如{‘required’:‘为空时显示的错误信息内容’}
    5. widget:html插件
    6. validators:自定义验证规则,里面放元组,与RegexValidator联用
  • CharField
    1. max_length:最大长度
    2. min_length:最小长度
    3. strip:是否移除空白
    4. widget:设置标签type参数以及添加属性,默认为text,`* TextInput(字典):设置标签type参数为text,同时可以添加自定义属性或样式,如:widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'})* PasswordInput():设置标签type参数为password,如:widget=forms.widgets.PasswordInput()`
  • ChoiceField/MultipleChoiceField
    1. choices :choices参数,如:choices = ((0,'上海'),(1,'北京'),)
    2. required:是否必填
    3. widget:插件,默认为select
      • RadioSelect():标签type参数为radio
      • Select():select下拉框标签
      • CheckboxInput():是否记住密码
      • SelectMultiple():select下拉框标签多选
      • CheckboxSelectMultiple:标签type参数为checkbox
  • EmailField

    必须是邮箱格式

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()

(2)内置的校验器

  1. 通过validators参数指向设置校验器,列表形式,可以放多个
  2. RegexValidator(正则表达式,条件未满足时输出的字符串)
from django.core.validators import RegexValidator

class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )

(3)HOOK方法

  • 局部钩子函数

    1. 校验单个字段
    2. 在Form类中定义clean_字段名()方法
    3. cleaned_data:前面两种筛选均满足的数据,字典形式存储
    4. 通过ValidationError(错误信息)直接抛出错误,源码内部做了异常捕捉
    5. 通过add_error(字段名,错误信息)方法添加错误
    from django.core.exceptions import ValidationError
    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):
            username = self.cleaned_data.get('username')
            if '666' in username:
                # 给username所对应的框展示错误信息
                # self.add_error('username','光喊666是不行的')
                raise ValidationError('到底对不对啊')
            # 将username数据返回
            return username
  • 全局钩子函数

    1. 对多个字段进行校验
    2. 在Form类中定义clean()方法
  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 = 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

(二)渲染标签

(1)后端

  1. POST请求前后form对象名要相同,方便后续错误信息展示和保存信息状态
  2. is_valid:是否满足匹校验条件,返回布尔值
# views.py
def index(request):
    # 渲染标签 第一步 需要生成一个空的forms类的对象
    form_obj = MyForm()
    # 如何校验前端用户传入的数据
    if request.method == 'POST':
        # 获取用户的数据  request.POST中  forms组件校验数据
        form_obj = MyForm(request.POST)  # 改变量名一定要跟上面的form_obj变量名一直
        if form_obj.is_valid():  # 研究forms组件入口就是is_valid()
            print(form_obj.cleaned_data)
            return HttpResponse('数据全部OK')
    # 直接将生成的对象 传递给前端页面
    return render(request,'index.html',locals())

(2)前端

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

  • 方式1(内置方法)

    方式1封装程度太高,扩展性差,不推荐使用

    1. as_p:作为p标签
    2. as_ul:作为列表标签
    3. as_table:作为表格表头标签,效果为横向一排
    {{ form_obj.as_p }}  <!--自动渲染所有input框  -->
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
  • 方式2(label属性)

    方式2在输入项目过多时过于冗杂,也不推荐使用

    {{ form_obj.username.label }}{{ form_obj.username }}
    {{ form_obj.username.label }}{{ form_obj.password }}
    {{ form_obj.username.label }}{{ form_obj.email }}
    
  • 方式3(for循环)

    推荐使

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

(三)展示信息

  1. 空的Form对象和POST请求后的Form对象名要相同
  2. errors:错误信息,返回列表
  3. form表单中novalidate参数:取消前端校验
<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组件模板

(一)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()

四、附录

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀

CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白

IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值

FloatField(IntegerField)
    ...

DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度

BaseTemporalField(Field)
    input_formats=None          时间格式化   

DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12

DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...

RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}

EmailField(CharField)
    ...

FileField(Field)
    allow_empty_file=False     是否允许空文件

ImageField(FileField)
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)

URLField(Field)
    ...

BooleanField(Field)
    ...

NullBooleanField(BooleanField)
    ...

ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示

ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选

ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField

TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值

MultipleChoiceField(ChoiceField)
    ...

TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值

ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])

MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用

SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']

FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''

GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...

UUIDField(CharField)           uuid类型

Django Form内置字段

(day57)九、多对多创建的三种方式、Forms组件的更多相关文章

  1. 于Unity3D动态创建对象和创建Prefab三种方式的原型对象

    于Unity3D动态创建对象和创建Prefab三种方式的原型对象 u3d在动态创建的对象,需要使用prefab 和创建时 MonoBehaviour.Instantiate( GameObject o ...

  2. 黑马vue---56-58、vue组件创建的三种方式

    黑马vue---56-58.vue组件创建的三种方式 一.总结 一句话总结: 不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素 1.使用 Vu ...

  3. 【Java EE 学习 52】【Spring学习第四天】【Spring与JDBC】【JdbcTemplate创建的三种方式】【Spring事务管理】【事务中使用dbutils则回滚失败!!!??】

    一.JDBC编程特点 静态代码+动态变量=JDBC编程. 静态代码:比如所有的数据库连接池 都实现了DataSource接口,都实现了Connection接口. 动态变量:用户名.密码.连接的数据库. ...

  4. SpringBoot工程创建的三种方式

    一. 通过IDEA的spring Initializer创建 1. 打开创建项目面板 File->New->Project->Spring Initializr 2. 填写Maven ...

  5. wpf 创建动画三种方式

    动画类型 : 故事版,CompositionTarget,DispachTime 那么到此,三种动态创建动画的方法都已经详细介绍过了,大家可能会有种感觉,比较钟情于第一种WPF/Silverlight ...

  6. React: React组件创建的三种方式

    一.简介 在前面介绍的React组件知识中,对于组件的创建我只是用了其中某一种方式.其实,在2013年React诞生之初,对于React组件的创建,仅仅只有一种方式,也即createClass函数,在 ...

  7. 51、多线程创建的三种方式之实现Callable接口

    实现Callable接口创建线程 Callable接口是在jdk5版本中加入的,这个接口在java.util.concurrent包下面,与其他两种方式不同的地方在于使用Callable接口创建的线程 ...

  8. vue组件创建的三种方式

    1.使用Vue.extend创建全局的Vue组件 //1.1 使用vue.extend创建组件 var com1 = Vue.extend({ //通过template属性指定组件要展示的html结构 ...

  9. IOS第12天(1,UIViewController控制器的创建的 三种方式,和第一个view创建)

    *************HMAppDelegate.m中 @implementation HMAppDelegate - (BOOL)application:(UIApplication *)app ...

随机推荐

  1. ASP.NET Core Web 应用程序系列(五)- 在ASP.NET Core中使用AutoMapper进行实体映射

    本章主要简单介绍下在ASP.NET Core中如何使用AutoMapper进行实体映射.在正式进入主题之前我们来看下几个概念: 1.数据库持久化对象PO(Persistent Object):顾名思义 ...

  2. Java内存区域与内存溢出异常,对象的创建

    一.运行时数据区域 Java程序的执行流程:首先 .java源代码文件会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执 ...

  3. jQuery随笔记录

            DOM遍历 parent()方法返回所选元素的直接父元素.(parent() 只能遍历单个级别的 DOM树) parents()方法获取所选元素的所有祖先 children()所选元素 ...

  4. [转]RPA Developer Advanced Certification - Exam #1 UiPath 练习

    本文转自:https://github.com/miyaichi/CertificationExam1 RPA Developer Advanced Certification - Exam #1 E ...

  5. Android WebView与H5联调技巧

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/78 背景: 突然想写一篇关于Android WebView ...

  6. linux终端 tty pty pts等

    linux终端 tty pty pts等 20140608 Chenxin整理 系统变量TERM不知是用来干什么的?它的值有vt100,vt220等,这些值代表什么意思? 环境变量TERM设置为终端机 ...

  7. TP事物的写法

    Db::startTrans(); try{ Db::commit(); } catch (\Exception $e) { Db::rollback(); } use think\Db; publi ...

  8. V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245.1)

    V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245. ...

  9. win 10 命令行导出注册表

    命令如下: reg  export  注册表中的key  保存路径 reg export HKLM\Software\MyCo\MyApp AppBkUp.reg 如果需要直接覆盖原来的文件,可以加上 ...

  10. Redis学习笔记(九、Redis总结)

    1.Redis五大对象: 在Redis中有五大对象,分别是String.List.Hash.Set.Sorted Set. 这五大对象都有自己独特的编码方式,每个编码的实现都不一样,有自己独特的使用场 ...