model form
ModelForm 能允许我们通过一个 Model 直接创建一个和该模型的字段一一对应的表单,大大方便了表单操作。
下面来看一个例子。
首先我们有这样的 model:
from django.db import models
TITLE_CHOICES = (
('MR', 'Mr.'),
('MRS', 'Mrs.'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.name
一、ModelForm的用法
ModelForm对用户提交的数据有验证功能,但比Form要简单的多
from
django.forms
import
ModelForm
# 导入ModelFormclass
customerModelForm(ModelForm):
class
Meta:
model
=
models.UserInfo
fields
=
"__all__"
labels
=
{
'name'
:
'用户名'
,
'password'
:
'密码'
,
'qq'
:
'qq号'
,
'微信'
:
'微信号'
,
'roles'
:
'角色'
}
说明:
1.model:对应得表名
2.fields:选择字段列表,'__all__'是选择所有字段
3.exclude:排除字段列表
4.widgets:插件列表
5.labels:前端显示字段名
6.error_messages:自定义错误提示
7.localized_field:本地化,如:根据不同时区显示数据
除了这些参数,ModelForm和Form一样可以定义局部钩子和全局钩子
2.实例化表单对象,传入模板,同Form
model_form
=
customerModelForm()return
render(request,
"index.html"
,{
"model_form"
:model_form})
3、前端通过传递的model_form展示
<div class="row">
{{ model_form.errors }}
<form class="form-horizontal" method="post" >
{% csrf_token %}
{% for field in model_form %}
<div class="form-group">
<label class="col-sm-2 " style="font-weight: normal">
{% if field.field.required %}
<b> {{ field.label }} (*必填项) </b>
{% else %}
{{ field.label }}
{% endif %}
</label>
<div class="col-sm-10">
<span style="color: red;">{{ field.errors }}</span>
{{ field }}
</div>
</div>
{% endfor %}
</form>
</div>
4、form提交后,后端view通过以下方式,验证提交的表单
model_form
=
customerModelForm(request.POST)
if
model_form.is_valid():
model_form.save()
5.如果是修改记录,则需要传入记录对象
obj = customerModel.objects.get(id=obj_id) #查到原来的值
model_form
=
customerModelForm(instance
=
user_obj) #传入值
model_form
=
customerModelForm(request.POST, instance
=
obj) #将原来的值生成新值
if
model_form.is_valid():
model_form.save()
|
二、有多个Model,不想要每个model写一个ModelForm的,采用动态生成ModelForm类的方法
A、动态生成类的函数:type('classname',(object,),dict(funname=fun))
参数:
1、class的名称,字符串形式;
2、继承的父类集合,注意Python支持多重继承,如果只有一个父类,注意tuple的单元素写法;
3、class的方法名称与函数绑定,这里我们把函数fun绑定到方法名funname上,可以采用:
setattr(classname,"funname",fun)方式替代 例子:
def CreateModelForm(request,admin_obj):
class Meta:
model = admin_obj.model
fields = "__all__" def __new__(cls, *args, **kwargs):
for field_name,field_obj in cls.base_fields.items():
field_obj.widget.attrs['class'] = 'form-control'
if field_name in admin_obj.readonly_fields:
field_obj.widget.attrs['disabled'] = True #在后台不能通过这种方式修改外键对应的字段,比如consultant
return forms.ModelForm.__new__(cls) def default_clean(self):
print("cleaned data:",self.cleaned_data) dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,), {"Meta":Meta})
setattr(dynamic_model_form,"__new__",__new__)
setattr(dynamic_model_form,"clean",default_clean)
return dynamic_model_form 上述例子就可以根据需求动态生成dynamic_model_form了,需要使用的时候调用CreateModelForm函数即可
model_form = forms.CreateModelForm(request,admin_obj=admin_obj)
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
def __str__(self):
return self.name
我们根据上面的 Model 用 ModelForm 来直接创建表单,下面编写 forms.py:
from django.forms import ModelForm
from myApp.models import Author, Book
class AuthorForm(ModelForm):
class Meta:
model = Author # 根据 Author 模型创建表单
fields = ['name', 'title', 'birth_date'] # 该表单包含的字段
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['name', 'authors']
现在看看表单在前端的效果。
编写 views.py:
from django.shortcuts import render
from myApp.forms import AuthorForm, BookForm
def test(request):
context = {}
author_form = AuthorForm()
book_form = BookForm()
context['author_form'] = author_form
context['book_form'] = book_form
return render(request, 'test.html', context)
编写 test.html:
<body>
<h2>Author Form:</h2>
{{ author_form }}
<br><br>
<h2>Book Form:</h2>
{{ book_form }}
</body>
页面如下:

ModelForm 的 save() 方法
ModelForm 的 save() 方法大体上和普通 Form 的 save() 没有区别,但 ModelForm 对象可以接受 commit 和 instance 参数来处理一些特殊的情况。
- **instance **
ModelForm 的子类可以用关键字参数 instance 接收一个已经存在的 Model 实例;如果使用 instance 参数,save() 将更新这个实例;如果不使用,save() 将创建一个新的 Model 实例
下面我们在 shell 中演示一下 instance 的用法:
from myApp.models import Author, Book
from myApp.forms import AuthorForm, BookForm
# 获取主键=1的 Model 对象
a = Author.objects.get(pk=1)
# 使用 instance 参数,调用 save() 方法将更新 a 对象
af = AuthorForm({'name':'鲁迅', 'title':'MR', }, instance=a)
af.save()
# 不使用 instance 参数,调用 save() 方法将创建一个新的对象
af = AuthorForm({'name':'鲁迅', 'title':'MR', })
af.save()
注意,如果表单没有验证,save() 调用将通过检查 form.errors 来进行验证。如果表单中的数据不合法,将引发 ValueError —— 例如,如果 form.errors 为True。
我们来试试构造一个错误的表单,看看 errors 信息:
af = AuthorForm({'name':'鲁迅', 'title':'12345', })
af.errors
>>> {'title': ['Select a valid choice. 12345 is not one of the available choices.']}
- **commit **
save() 有一个可选的 commit 关键字参数,其值为 True 或 False(默认为 True)。
如果调用 save() 时 commit=False,那么它将返回一个还没有保存到数据库的 Model 对象。这种情况下,你需要调用 Model 实例本身的 save() 方法。 如果你想在保存之前自定义一些处理,或者你想使用特定的模型保存选项,就可以使用 commit=False。
下面在 shell 中演示:
af = AuthorForm({'name':'鲁迅', 'title':'MR', })
# 用 commit=False 调用 save() 方法,这时 af 并不会保存到数据库
af = af.save(commit=False)
# 查看 af 的类型,可见 af 是一个 Model 的实例
af
>>> <Author: 鲁迅>
type(af)
>>> <class 'myApp.models.Author'>
# 查看该 Model 实例的属性
af.name
>>> '鲁迅'
# 手动修改 Model 实例的属性
af.name = '周树人'
# 调用 Model 实例本身的 save() 方法,这时实例被保存到数据库了
af.save()
选择用到的字段
使用 fields 属性表示需要使用 Model 的哪些字段:
class AuthorForm(ModelForm):
class Meta:
model = Author
# 表示该模型的全部字段都被表单使用
fields = '__all__'
如果只要使用某些字段,可以这样:
fields = ['name', 'title', ]
使用 exclude 属性可以排除不需要用的字段:
class AuthorForm(ModelForm):
class Meta:
model = Author
# 排除掉 birth_date 字段
exclude = ['birth_date']
使用上面两种方法,表单中字段出现的顺序将和字段在模型中定义的顺序一致。
如果设置了 Model 字段的 editable=False,那么使用 ModelForm 从该模型创建的任何表单都不会包含该字段。
重写(覆盖)默认的字段
使用内部类 Meta 的 widgets 属性可以指定一个字段的自定义 Widget。
例如,Author 的 name 属性为 CharField,如果你希望它表示成一个 <textarea> 而不是默认的 <input type="text">,你可以覆盖字段默认的 Widget:
from django.forms import ModelForm, Textarea
from myApp.models import Author, Book
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
widgets = {
'name': Textarea(attrs={'cols': 80, 'rows': 20}),
}
类似地,如果你希望进一步自定义字段,你可以指定内部类 Meta 的 labels、help_texts 和 error_messages:
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
labels = {
'name': '作者',
'title': '头衔',
'birth_date': '出生日期',
}
error_messages = {
'name': {
'max_length': "名字长度应在15个字符以内",
},
}
最后,如果你希望完全控制字段 —— 包括它的类型、验证器等等,你可以像在普通的表单那样显式指定字段。
例如,如果你想为 slug 字段使用 SlugField,可以像下面这样:
class AuthorForm(ModelForm):
slug = forms.SlugField()
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
如果想要指定字段的验证器,可以显式定义字段并设置它的 validators 参数:
class AuthorForm(ModelForm):
slug = forms.SlugField(validators=[validate_slug])
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
modelform_factory 函数
可以单独使用 modelform_factory() 函数来直接从 Model 创建表单。在不需要很多自定义的情况下是更方便的:
from myApp.models import Author, Book
from django.forms.models import modelform_factory
BookForm = modelform_factory(Book, fields=("name", "authors"))
这样就根据 Book 的模型创建了表单 BookForm。
还可以对表单类做简单的修改,比如,对给出的字段指定 widgets :
BookForm = modelform_factory(
Book,
fields=("name", "authors"),
widgets={"name": Textarea()}
)
作者:SingleDiego
链接:https://www.jianshu.com/p/3d04309445e4
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
通过一个内嵌类 "class Meta" 给你的 model 定义元数据, 类似下面这样:
class Foo(models.Model):
bar = models.CharField(maxlength=30) class Meta:
# ...
Model 元数据就是 "不是一个字段的任何数据" -- 比如排序选项, admin 选项等等. 下面是所有可能用到的 Meta 选项. 没有一个选项是必需的. 是否添加 class Meta 到你的 model 完全是可选的. app_label
app_label这个选项只在一种情况下使用,就是你的模型类不在默认的应用程序包下的models.py文件中,这时候你需要指定你这个模型类是那个应用程序的。比如你在其他地方写了一个模型类,而这个模型类是属于myapp的,那么你这是需要指定为: app_label='myapp'
db_table
db_table是用于指定自定义数据库表名的。Django有一套默认的按照一定规则生成数据模型对应的数据库表名,如果你想使用自定义的表名,就通过这个属性指定,比如: table_name='my_owner_table'
若不提供该参数, Django 会使用 app_label + '_' + module_name 作为表的名字. 若你的表的名字是一个 SQL 保留字, 或包含 Python 变量名不允许的字符--特别是连字符 --没关系. Django 会自动在幕后替你将列名字和表名字用引号引起来. db_tablespace
有些数据库有数据库表空间,比如Oracle。你可以通过db_tablespace来指定这个模型对应的数据库表放在哪个数据库表空间。 get_latest_by
由于Django的管理方法中有个lastest()方法,就是得到最近一行记录。如果你的数据模型中有 DateField 或 DateTimeField 类型的字段,你可以通过这个选项来指定lastest()是按照哪个字段进行选取的。 一个 DateField 或 DateTimeField 字段的名字. 若提供该选项, 该模块将拥有一个 get_latest() 函数以得到 "最新的" 对象(依据那个字段): get_latest_by = "order_date"
managed
由于Django会自动根据模型类生成映射的数据库表,如果你不希望Django这么做,可以把managed的值设置为False。 默认值为True,这个选项为True时Django可以对数据库表进行 migrate或migrations、删除等操作。在这个时间Django将管理数据库中表的生命周期 如果为False的时候,不会对数据库表进行创建、删除等操作。可以用于现有表、数据库视图等,其他操作是一样的。 order_with_respect_to
这个选项一般用于多对多的关系中,它指向一个关联对象。就是说关联对象找到这个对象后它是经过排序的。指定这个属性后你会得到一个get_XXX_order()和set_XXX_order()的方法,通过它们你可以设置或者回去排序的对象。 举例来说, 如果一个 PizzaToppping 关联到一个 Pizza 对象, 这样做: order_with_respect_to = 'pizza'
...就允许 toppings 依照相关的 pizza 来排序. ordering
这个字段是告诉Django模型对象返回的记录结果集是按照哪个字段排序的。比如下面的代码: ordering=['order_date']
# 按订单升序排列
ordering=['-order_date']
# 按订单降序排列,-表示降序
ordering=['?order_date']
# 随机排序,?表示随机
ordering = ['-pub_date', 'author']
# 对 pub_date 降序,然后对 author 升序
需要注意的是:不论你使用了多少个字段排序, admin 只使用第一个字段 permissions
permissions主要是为了在Django Admin管理模块下使用的,如果你设置了这个属性可以让指定的方法权限描述更清晰可读。 要创建一个对象所需要的额外的权限. 如果一个对象有 admin 设置, 则每个对象的添加,删除和改变权限会人(依据该选项)自动创建.下面这个例子指定了一个附加权限: can_deliver_pizzas: permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
这是一个2-元素 tuple 的tuple或列表, 其中两2-元素 tuple 的格式为:(permission_code, human_readable_permission_name). unique_together
unique_together这个选项用于:当你需要通过两个字段保持唯一性时使用。这会在 Django admin 层和数据库层同时做出限制(也就是相关的 UNIQUE 语句会被包括在 CREATE TABLE 语句中)。比如:一个Person的FirstName和LastName两者的组合必须是唯一的,那么需要这样设置: unique_together = (("first_name", "last_name"),)
verbose_name
verbose_name的意思很简单,就是给你的模型类起一个更可读的名字: verbose_name = "pizza"
若未提供该选项, Django 则会用一个类名字的 munged 版本来代替: CamelCase becomes camel case. verbose_name_plural
这个选项是指定,模型的复数形式是什么,比如: verbose_name_plural = "stories"
若未提供该选项, Django 会使用 verbose_name + "s".
表单输出选项 {{ form.as_table }}:以表格形式加载表单元素 {{ form.as_p }}:以段落形式加载表单元素 {{ form.as_ul }:以列表形式加载表单元素 表单相关的属性 {{ field.label }}:字段对应的<lable>标签的文字,例如“发件人”。 {{ field.label_tag }}:字段对应的<lable>标签。 {{ field.id_for_label }}:字段的“id”属性值。 {{ field.value }}:字段的值,例如标题的内容。 {{ field.html_name }}:字段对应的HTML标签“name”属性的值。 {{ field.help_text }}:字段的帮助文本。 {{ field.errors }}:包含任何字段验证错误的全部信息,可以通过“{% for error in field.errors %}”的方式遍历。 {{ field.is_hidden }}:字段是否隐藏字段,获取到的是布尔值。 {{ field.field }}:字段对象,可以通过它访问字段的属性,例如“{{ field.field.max_length }}”,“{{ field.field.required}}”。
model form的更多相关文章
- Django的model form组件
前言 首先对于form组件通过全面的博客介绍,对于form我们应该知道了它的大致用法,这里我们需要明确的一点是,我们定义的form与model其实没有什么关系,只是在逻辑上定义form的时候字段名期的 ...
- model.form使用,配合form的钩子
一次model.form的使用记录,配合form钩子的过程 在写信息采集功能的时候,需要添加资产信息,使用modelform组件减少工作量 官网介绍:版本1.9.https://docs.django ...
- Django Model Form
ModelForm ModelForm结合了Form和Model,将models的field类型映射成forms的field类型,复用了Model和Model验证, 写更少的代码,并且还实现了存储数据 ...
- django model form 保存方法 django-rest-framework save 修改某一项值 方法
django Model Form django-rest-framework save 方法 修改某个数据的值
- python3-开发进阶Django-form组件中model form组件
Django的model form组件 这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来,先来一个简单的例子来看一下这个东西怎么用:比如我们的数据库中有这样 ...
- Django 的 model form 组件
Django 的 model form 组件 Model Form 组件的由来 之前介绍过 Django 的 Form 组件(Django的Form表单)使用方法,Form 组件能够帮我们做三件事: ...
- 14 Django之Form和Model Form组件
一.什么是Form 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用 ...
- Model&Form&ModelForm拾遗
Model&Form&ModelForm拾遗 一.Model&Form&ModelForm Model:用于用户请求数据的验证(针对性弱),但有强大的数据库操作 For ...
- 自定义django model form、admin action
https://www.cnblogs.com/0zcl/archive/2017/03/22/6580279.html 先看效果图: 登陆admin后的界面: 查看作者: 当然你也可以定制admin ...
- Django之model.form创建select标签
前言 之前我们学习了form表单验证用户输入格式和自动创建HTML,那么如果用户创建select标签时怎么办呢,先来看下这个东西: models.py 数据格式: class UserInfo(mod ...
随机推荐
- 从头学pytorch(三) 线性回归
关于什么是线性回归,不多做介绍了.可以参考我以前的博客https://www.cnblogs.com/sdu20112013/p/10186516.html 实现线性回归 分为以下几个部分: 生成数据 ...
- 数据库基础之Mysql
数据库的简介 数据库 数据库(database,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合.数据库中的数据按一定的数学模型组织.描述和存储,具有较小的冗余,较高的数据独立性和易扩展性, ...
- 深入ThreadLocal的底层实现机制以及对应的使用风险
学习Java中常用的开源框架,Mybatis.Hibernate中线程通过数据库连接对象Connection,对其数据进行操作,都会使用ThreadLocal类来保证Java多线程程序访问和数据库数据 ...
- spring boot(三)Junit 测试controller
Junit测试Controller(MockMVC使用),传输@RequestBody数据解决办法 一.单元测试的目的 简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期 ...
- Python 多态与抽象类
一.多态 1.1 什么是多态 多态也称"多态性",指的是同一种类型的事物,不同的形态. 在python中的多态指的是让多种类若具备类似的数据属性与方法属性,都统一好命名规范,这样可 ...
- 【题解】P5589 小猪佩奇玩游戏(期望)
[题解]P5589 小猪佩奇玩游戏(期望) 假设一个点有\(x\)个点(包括自己)可以到达他,他就对答案有\(1/x\)的贡献.这是因为这个点必须被删掉而通过删掉这个点本身删掉这个点的概率是\(1/x ...
- 「Luogu P3183」[HAOI2016]食物链 解题报告
身为一个蒟蒻,由于刷不过[NOI2001]食物链 于是出门左转写了道另一道假的食物链 戳这里 这里的食物链个条数其实就是有向图的路径数(应该是这么说吧,我弱) 思路: 拓扑(Topulogy)(一本正 ...
- 用积分方法求K次方和数列公式
这是我很早以前在高中时发现的一个通用计算K次方和数列公式的方法,很特别的地方是用了微积分中的积分方法.目前我还没有发现有谁提出和我一样的方法,如果哪位读者有相关发现,麻烦告知我. 大家很多人都知道高斯 ...
- @Configuration结合@Bean实现对象的配置
@Configuration结合@Bean实现对象的配置 前提:最近项目中需要做支付接口,支付宝以及微信支付,本文并不介绍如何写支付接口,而是通过这个示例讲解配置应该怎么写,项目中使用的是Kotlin ...
- The command '/bin/sh -c unzip -o php-7.2.23-src.zip' returned a non-zero code: 1
Dockerfile 内容 #centos7 nginx php redis inotify FROM centos:7 MAINTAINER INFOBIRD RUN yum -y update & ...