ModelForm组件
什么是ModelForm?
这是一个神奇的组件,通过名字我们可以看出来,这个组件的功能就是把model和form组合起来,先来一个简单的例子来看一下这个东西怎么用:比如我们的数据库中有这样一张学生表,字段有姓名,年龄,爱好,邮箱,电话,住址,注册时间等等一大堆信息,现在让你写一个创建学生的页面,你的后台应该怎么写呢?首先我们会在前端一个一个罗列出这些字段,让用户去填写,然后我们从后天一个一个接收用户的输入,创建一个新的学生对象,保存其实,重点不是这些,而是合法性验证,我们需要在前端判断用户输入是否合法,比如姓名必须在多少字符以内,电话号码必须是多少位的数字,邮箱必须是邮箱的格式这些当然可以一点一点手动写限制,各种判断,这毫无问题,除了麻烦我们现在有个更优雅(以后在Python相关的内容里,要多用“优雅”这个词,并且养成习惯)的方法:ModelForm先来简单的,生硬的把它用上,再来加验证条件。
一、创建表
models.py
from django.db import models class Book(models.Model): title=models.CharField(max_length=32) price=models.DecimalField(max_digits=8,decimal_places=2) # 999999.99 date=models.DateField() publish=models.ForeignKey("Publish") authors=models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name=models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name=models.CharField(max_length=32) def __str__(self): return self.name
二、创建modelform
views.py
from django.shortcuts import render,redirect from .models import * #首先导入ModelForm from django.forms import ModelForm from django.forms import widgets as wid #在视图函数中,定义一个类,比如就叫StudentList,这个类要继承ModelForm,在这个类中再写一个原类Meta(规定写法,并注意首字母是大写的) #在这个原类中,有以下属性(部分): class BookForm(ModelForm): class Meta: model=Book #对应的Model中的类 fields="__all__" #字段,如果是__all__,就是表示列出所有的字段 # labels,自定义在前端显示的名字 labels={"title":"书籍名称", "price":"价格"} # widgets用法,使用前先导入 widgets={ "title":wid.TextInput(attrs={"class":"form-control"}), #自定义属性 "price":wid.TextInput(attrs={"class":"form-control"}), "date":wid.TextInput(attrs={"class":"form-control","type":"date"}), "publish":wid.Select(attrs={"class":"form-control"}), "authors":wid.SelectMultiple(attrs={"class":"form-control"}), } # error_messages用法: error_messages={ "title":{"required":"不能为空"}, "price":{"invalid":"请输入数字"} }
三、基于ModelForm的增加和编辑
urls.py
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^books/', views.books), url(r'^book/add', views.addbook), url(r'^book/edit/(\d+)', views.editbook), ]
views.py
def books(request): book_list=Book.objects.all() return render(request,"books.html",locals()) #基于modelform的增加 #保存数据的时候,不用挨个取数据了,只需要save一下 def addbook(request): if request.method=="POST": form = BookForm(request.POST) if form.is_valid(): form.save() # form.model.objects.create(request.POST) return redirect("/books/") else: return render(request, "add.html", locals()) form=BookForm() return render(request,"add.html",locals()) #基于modelform的编辑 #如果不用ModelForm,编辑的时候得显示之前的数据吧,还得挨个取一遍值,如果ModelForm, # 只需要加一个instance=obj(obj是要修改的数据库的一条数据的对象)就可以得到同样的效果 # 保存的时候要注意,一定要注意有这个对象(instance=obj),否则不知道更新哪一个数据 def editbook(request,edit_book_id): edit_book = Book.objects.filter(pk=edit_book_id).first() if request.method=="POST": form = BookForm(request.POST,instance=edit_book) #instance=edit_book告诉它做更新操作,而不是添加 if form.is_valid(): form.save() # edit_book.update(request.POST) return redirect("/books/") form=BookForm(instance=edit_book) #添加instance=edit_book不同的地方在于:当render的时候会把edit_book的每个值放到value中 return render(request,"edit.html",locals())
相关html
books.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <a href="/book/add"><button>添加书籍</button></a> <hr> <table border="1"> {% for book in book_list %} <tr> <td>{{ book.title }}</td> <td>{{ book.price }}</td> <td>{{ book.date|date:"Y-m-d" }}</td> <td>{{ book.publish.name }}</td> <td>{{ book.authors.all }}</td> <td><a href="/book/edit/{{book.pk}}"><button>编辑</button></a></td> </tr> {% endfor %} </table> </body> </html>
form.html
<form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> {{ field.label }} {{ field }} <span>{{ field.errors.0 }}</span> > <!--渲染错误信息--> </div> {% endfor %} <input type="submit"> </form>
add.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <h3>添加页面</h3> <div class="row"> <div class="col-md-4 col-md-offset-3"> {% include 'form.html' %} </div> </div> </body> </html>
edit.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h3>编辑页面</h3> {% include 'form.html' %} </body> </html>