一、ModelForm的基本用法示例:
from django import forms
from app01 import models
class BookModelForm(forms.ModelForm):
#必须是这个类名
class Meta:
# 告诉Django这个form类和那个model类对应
model = models.Book
# 告诉Django这个form类里面有哪些字段
fields = "__all__"
widgets = {
"publish_date": forms.widgets.DateInput(
# 给日期字段添加日期类型
attrs={"type": "date"}
)
}
labels = {
"title": "书名",
"price": "价格",
"publish_date": '出版日期',
"publisher": "出版社名称",
"authors": "作者"
}
error_messages = {
"title": {
"required": "书名不能为空"
}
}
# 通过修改类的初始化方法达到批量添加共同属性的目的
def __init__(self, *args, **kwargs):
super(BookModelForm, self).__init__(*args, **kwargs)
# for field_name in self.base_fields:
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
ModelForm所有属性:
class Meta:
model, # 对应Model的
fields=None, # 字段
exclude=None, # 排除字段
labels=None, # 提示信息
help_texts=None, # 帮助提示信息
widgets=None, # 自定义插件
error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
field_classes=None # 自定义字段类 (也可以自定义字段)
localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
ModelForm用于验证用户数据:is_valid()
model_form_obj = XXOOModelForm() //实例化对象
model_form_obj.is_valid() // 校验数据
model_form_obj.errors.as_json() //错误
model_form_obj.clean() //同Form组件中的属性
model_form_obj.cleaned_data // 同Form组件中的属性
ModelForm用于创建数据:save()
def add_book(request):
if request.method == "POST":
#直接传request.POST,进行ModelForm的实例化传参
form_obj = forms.BookModelForm(request.POST)
if form_obj.is_valid(): # 校验数据
form_obj.save() #直接就可以保存数据到数据库,包括多对多,多对一,一对一的关系
return redirect("/book_list/")
#ModelForm实例化对象
form_obj = forms.BookModelForm()
return render(request, "v2/add_book.html", locals())
ModelForm用于初始化:ModelForm(instance=model_obj)
def edit_book(request, pk):
book_obj = models.Book.objects.filter(id=pk).first()
#form_obj通过initial设置初始化的值,例如,图书管理系统中的编辑书籍功能,
#点击编辑后跳转到编辑书籍页面,跳转后需要用要编辑的书籍信息填充页面对应信息。
#不同于Form组件的是,ModelForm直接就可以传实例化的对象,而不需要将对象转化成字典的形式传。
form_obj = forms.BookModelForm(instance=book_obj)
return render(request, "v2/edit_book.html", locals())
ModelForm用于更新 :ModelForm(request.POST, instance=book_obj)
def edit_book(request, pk):
book_obj = models.Book.objects.filter(id=pk).first()
if request.method == "POST":
#修改数据时,直接可以将用户数据包request.POST传进去,
#再传一个要修改的对象的示例,ModelForm就可以自动完成修改数据了。
form_obj = forms.BookModelForm(request.POST, instance=book_obj)
if form_obj.is_valid(): // 数据校验
form_obj.save() // 直接保存
return redirect("/book_list/")
#form_obj通过initial设置初始化的值,例如,图书管理系统中的编辑书籍功能,
#点击编辑后跳转到编辑书籍页面,跳转后需要用要编辑的书籍信息填充页面对应信息。
#不同于Form组件的是,ModelForm直接就可以传实例化的对象,而不需要将对象转化成字典的形式传。
form_obj = forms.BookModelForm(instance=book_obj)
return render(request, "v2/edit_book.html", locals())
二、ModelForm和Form组件的应用场景:
- ModelForm ---- 中小型应用程序。因为ModelForm是依赖于models的。
- Form ------- 大型应用程序
三、通过ModelForm实现的书籍、作者、出版社的管理代码示例:
- 表结构:
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=12)
address = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=12)
gender = models.SmallIntegerField(
choices=((0, '女'), (1, '男'), (2, '保密'))
)
age = models.IntegerField()
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2) # 0~999.99
publish_date = models.DateField()
publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)
authors = models.ManyToManyField(to="Author")
def __str__(self):
return self.title
- ModelForm类:
from django import forms
from app01 import models
class BookModelForm(forms.ModelForm):
class Meta:
# 告诉Django这个form类和那个model类对应
model = models.Book
# 告诉Django这个form类里面有哪些字段
fields = "__all__"
widgets = {
"publish_date": forms.widgets.DateInput(
# 给日期字段添加日期类型
attrs={"type": "date"}
)
}
labels = {
"title": "书名",
"price": "价格",
"publish_date": '出版日期',
"publisher": "出版社名称",
"authors": "作者"
}
error_messages = {
"title": {
"required": "书名不能为空"
}
}
# 通过修改类的初始化方法达到批量添加共同属性的目的
def __init__(self, *args, **kwargs):
super(BookModelForm, self).__init__(*args, **kwargs)
# for field_name in self.base_fields:
for field_name in iter(self.fields):
field = self.base_fields[field_name]
field.widget.attrs.update({
"class": "form-control",
})
- views 视图函数:
from django.shortcuts import render,redirect
from app01 import modelform
from app01 import models
def book_list(request):
book_list = models.Book.objects.all()
return render(request, 'book_list.html', {'book_list': book_list})
def add_book(request):
if request.method == "POST":
# modelform 直接可以将从前端拿到的数据组request.POST
#当参数传给实例化的Modelform
form_obj = modelform.BookModelForm(request.POST)
# 调用is_valid()方法校验数据
if form_obj.is_valid():
# 直接保存到数据库中
form_obj.save()
return redirect("/book_list/")
modelform_obj = modelform.BookModelForm()
return render(request, 'add_book.html', {"modelform_obj": modelform_obj})
def edit_book(request,pk):
book_obj = models.Book.objects.filter(id=pk).first()
if request.method == "POST":
#修改数据时,直接可以将用户数据包request.POST传进去,
#再传一个要修改的对象的示例,ModelForm就可以自动完成修改数据了。
form_obj = modelform.BookModelForm(request.POST, instance=book_obj)
if form_obj.is_valid():
form_obj.save()
return redirect("/book_list/")
# form_obj通过initial设置初始化的值,例如,图书管理系统中的编辑书籍功能,
# 点击编辑后跳转到编辑书籍页面,跳转后需要用要编辑的书籍信息填充页面对应信息。
# 不同于Form组件的是,ModelForm直接就可以传实例化的对象,而不需要将对象转化成字典的形式传。
form_obj = modelform.BookModelForm(instance=book_obj)
#locals()是将本地数据键值对的简写形式
return render(request, "edit_book.html", locals())
- book_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>书籍列表</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-offset-2">
<a href="/add_book/">添加书籍</a>
<table border="1">
<thead>
<tr>
<th>序号</th>
<th>id</th>
<th>书名</th>
<th>价格</th>
<th>出版日期</th>
<th>出版社</th>
<th>作者</th>
<th>操作</th>
</tr>
</thead>
{% for book in book_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
<td>{{ book.price }}</td>
<td>{{ book.publish_date }}</td>
<td>{{ book.publisher }}</td>
<td>{{ book.authors.all }}</td>
<td>
<a href="/edit_book/{{ book.id }}/">编辑</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
</body>
</html>
- add_book.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加书籍</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-offset-3">
<form role="form" action="" method="post">
{% csrf_token %}
{% for modelform in modelform_obj %}
<p>
{{ modelform.label }}
{{ modelform }}
</p>
{% endfor %}
<button type="submit" class="btn btn-success">提交</button>
</form>
</div>
</div>
</div>
</body>
</html>
- edit_book.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加书籍</title>
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-offset-3">
<form role="form" action="" method="post">
{% csrf_token %}
{% for filed in form_obj %}
<p>
{{ filed.label }}
{{ filed }}
</p>
{% endfor %}
<button type="submit" class="btn btn-success">提交</button>
</form>
</div>
</div>
</div>
</body>
</html>
四、通过对Form组件和ModelForm的对比
- ModelForm增加了Form组件和对应数据库之间的联系,进而简化了Form类的代码
- ModelForm继承了Form组件中的所有方法的同时,简化了前端获取数据和对应数据库之间的数据对接,不需要在对数据的内容做过多的操作。
五、ModelForm中的骚操作(同Form组件)
-
批量添加样式:
通过重写ModelForm类的init方法来实现。
# 通过修改类的初始化方法达到批量添加共同属性的目的
def __init__(self, *args, **kwargs):
super(BookModelForm, self).__init__(*args, **kwargs)
# for field_name in self.base_fields:
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
更多Django的Modelform相关内容请参考django的官方文档:
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/