modelform的简介
Form介绍
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。
与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
Django form组件就实现了上面所述的功能。
总结一下,其实form组件的主要功能如下:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
普通方式手写图书管理系统的增加书籍和编辑书籍功能
views.py,
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":
title = request.POST.get("title")
price = request.POST.get("price")
publish_date = request.POST.get("publish_date")
publisher = request.POST.get("publisher")
authors = request.POST.get("authors")
# 数据库中的数据
book_obj = models.Book.objects.create(
title=title,
price=price,
publish_date=publish_date,
publisher_id=publisher,
)
book_obj.authors.add(*authors)
return redirect("/book_list/")
publisher_list = models.Publisher.objects.all()
author_list = models.Author.objects.all()
return render(request,"add_book.html",{"publisher_list":publisher_list,"author_list":author_list})
# 编辑出版社
def edit_book(request, pk):
book_obj = models.Book.objects.filter(id=pk).first()
if request.method == "POST":
title = request.POST.get("title")
price = request.POST.get("price")
publish_date = request.POST.get("publish_date")
publisher = request.POST.get("publisher")
authors = request.POST.getlist("authors") # 什么时候用getlist/多选的checkbox也是
book_obj.title = title
book_obj.price = price
book_obj.publish_date = publish_date
book_obj.publisher_id = publisher
book_obj.save()
book_obj.authors.set(authors)
return redirect("/book_list/")
publisher_list = models.Publisher.objects.all()
author_list = models.Author.objects.all()
return render(request, "edit_book.html", locals())
book_list.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>书籍列表</title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/pub.css"> </head> <body> {% include 'nav.html' %} <div class="container-fluid"> <div class="row"> <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li><a href="/publisher/">出版社管理 <span class="sr-only">(current)</span></a></li> <li class="active"><a href="/book_list/">书籍管理</a></li> <li><a href="/author_list/">作者管理</a></li> </ul> </div> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="panel panel-primary"> <div class="panel-heading"> <h2 class="panel-title">书籍列表</h2> </div> <div class="panel-body"> <div class="row"> <div class="col-lg-3"> <div class="input-group"> <input type="text" class="form-control" placeholder="搜索"> <span class="input-group-btn"> <button class="btn btn-primary" type="button">Go</button> </span> </div><!-- /input-group --> </div> <div class="pull-right col-lg-1"> <a href="/add_book/" class="btn btn-info ">添加</a> </div> </div> <div class="table-responsive"> <table class="table table-striped table-hover"> <thead> <tr> <th>序号</th> <th>ID</th> <th>标题</th> <th>价格</th> <th>出版日期</th> <th>出版社</th> <th>作者</th> </tr> </thead> <tbody> {% 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.name }}</td> <td> {% for author in book.authors.all %} {% if forloop.last %} {{ author.name }} {% else %} {{ author.name }} | {% endif %} {% endfor %} </td> <td> <a href="/del_book/{{ book.id }}" class="btn btn-danger btn-sm">删除</a> <a href="/edit_book/{{ book.id }}" class="btn btn-warning btn-sm">编辑</a> </td> </tr> {% endfor %} </tbody> </table> </div> <div class="pull-right"> <nav aria-label="..."> <ul class="pagination"> <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a> </li> <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li> <li><a href="#">2</a></li> <li><a href="#">3</a></li> <li><a href="#">4</a></li> <li><a href="#">5</a></li> <li><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li> </ul> </nav> </div> </div> </div> </div> </div> </div> </body> </html>
edit_book.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>编辑书籍</title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/css/bootstrap.css"> </head> <body> {% include 'nav.html' %} <div class="container" style="margin-top: 100px"> <div class="row"> <div class="col-lg-6 col-lg-offset-3"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">编辑书籍</h3> </div> <div class="panel-body"> <div class="row"> <form class="form-horizontal" method="post" action=""> {% csrf_token %} <input type="text" name="id" value="{{ edit_book.id }}" style="display: none"> <div class="form-group"> <label for="publisher" class="col-sm-2 control-label">名称</label> <div class="col-sm-9"> <input type="text" class="form-control" id="publisher" name="title" value="{{ book_obj.title }}"> </div> </div> <div class="form-group"> <label for="price" class="col-sm-2 control-label">价格</label> <div class="col-sm-9"> <input type="text" class="form-control" id="price" name="price" value="{{ book_obj.price }}"> </div> </div> <div class="form-group"> <label for="date" class="col-sm-2 control-label">日期</label> <div class="col-sm-9"> <input type="date" class="form-control" id="date" name="date" value="{{ book_obj.publish_date|date:'Y-m-d' }}"> </div> </div> <div class="form-group"> <label for="publisher" class="col-sm-2 control-label">出版社</label> <div class="col-sm-9"> <select name="publish" id="" class="form-control"> {% for publish in publisher_list %} {% if publish.id == book_obj.publisher_id %} <option value="{{ publish.id }}" selected>{{ publish.name }}</option> {% else %} <option value="{{ publish.id }}">{{ publish.name }}</option> {% endif %} {% endfor %} </select> </div> </div> <div class="form-group"> <label for="publisher" class="col-sm-2 control-label">作者</label> <div class="col-sm-9"> <select name="authors" id="" class="form-control"> {% for author in author_list %} {% if author in book_obj.authors.all %} <option selected value="{{ author.id }}">{{ author.name }}</option> {% else %} <option value="{{ author.id }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">提交</button> </div> </div> <div class="row"> <p class="text-center text-danger">{{ err_msg }}</p> </div> </form> </div> </div> </div> </div> </div> </div> </body> </html>
add_book.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加书籍</title> <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/css/bootstrap.css"> </head> <body> {% include 'nav.html' %} <div class="container" style="margin-top: 100px"> <div class="row"> <div class="col-lg-6 col-lg-offset-3"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">增加书籍</h3> </div> <div class="panel-body"> <div class="row"> <form class="form-horizontal" method="post" action=""> {% csrf_token %} <div class="form-group"> <label for="publisher" class="col-sm-2 control-label">名称</label> <div class="col-sm-9"> <input type="text" class="form-control" id="publisher" name="title"> </div> </div> <div class="form-group"> <label for="price" class="col-sm-2 control-label">价格</label> <div class="col-sm-9"> <input type="text" class="form-control" id="price" name="price"> </div> </div> <div class="form-group"> <label for="publish_date" class="col-sm-2 control-label">日期</label> <div class="col-sm-9"> <input type="date" class="form-control" id="publish_date" name="publish_date"> </div> </div> <div class="form-group"> <label for="publisher" class="col-sm-2 control-label">出版社</label> <div class="col-sm-9"> <select name="publisher" id="" class="form-control"> {% for publish in publisher_list %} <option value="{{ publish.id }}">{{ publish.name }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <label for="authors" class="col-sm-2 control-label">作者</label> <div class="col-sm-9"> <select name="authors" id="" class="form-control"> {% for author in author_list %} <option value="{{ author.id }}">{{ author.name }}</option> {% endfor %} </select> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">提交</button> </div> </div> <div class="row"> <p class="text-center text-danger">{{ err_msg }}</p> </div> </form> </div> </div> </div> </div> </div> </div> </body> </html>
nav.html:
<nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">图书管理系统</a> </div> <div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Dashboard</a></li> <li><a href="#">Settings</a></li> <li><a href="#">Profile</a></li> <li><a href="#">Help</a></li> </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="Search..."> </form> </div> </div> </nav>
2、用form组件实现增改查:
要带入from django.forms.models import model_to_dict实现默认值的显示:
views.py代码:
# y用form组件的增加书籍 def add_book1(request): # 获取前端提交的数据 if request.method == "POST": # 不用一步一步写了,直接获取就行了 form_obj = forms.BookForm(request.POST) # 进行校验 if form_obj.is_valid(): # 因为authors是关联表里边的,不是书籍这张表里的,所以要把这个弹出去 authors = form_obj.cleaned_data.pop("authors") # 创建的时候,需要所有数据打散 book_obj = models.Book.objects.create(**form_obj.cleaned_data) book_obj.authors.add(*authors) return redirect("/book_list/") publisher_list = models.Publisher.objects.all() author_list = models.Author.objects.all() form_obj = forms.BookForm() return render(request, "add_book1.html", locals()) # y用form组件的编辑书籍 def edit_book1(request, pk): book_obj = models.Book.objects.filter(id=pk).first() obj_dict = model_to_dict(book_obj) print(obj_dict) # 能把你想要修改的那个对象获取出来 if request.method == "POST": form_obj = forms.BookForm(request.POST) if form_obj.is_valid(): title = form_obj.cleaned_data.get("title") price = form_obj.cleaned_data.get("price") publish_date = form_obj.cleaned_data.get("publish_date") publisher = form_obj.cleaned_data.get("publisher") authors = form_obj.cleaned_data.get("authors") book_obj.title = title book_obj.price = price book_obj.publish_date = publish_date book_obj.publisher_id = publisher book_obj.save() book_obj.authors.set(authors) return redirect("/book_list/") form_obj = forms.BookForm(initial=obj_dict) # 这个就是你原来的默认值 publisher_list = models.Publisher.objects.all() author_list = models.Author.objects.all() return render(request, "edit_book1.html", locals())
html代码,编辑和增加都一样:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加书籍</title> </head> <body> <form action="" method="post"> {% csrf_token %} {% for filed in form_obj %} <p> {{ filed.label }} {{ filed }} </p> {% endfor %} {{ form_obj.errors }} <p> <input type="submit"> </p> </form> </body> </html>
form.py中的一个属性也要改变:
class BookForm(forms.Form): title = forms.CharField(max_length=32, label="书名") price = forms.DecimalField(max_digits=5, decimal_places=2) publish_date = forms.DateField( # 这个是因为返回的页面要是date格式的 widget=forms.widgets.DateInput( attrs={"type": "date"} ) ) publisher = forms.ModelChoiceField( # choices=models.Publisher.objects.all().values_list("id","name"), # widget=forms.widgets.Select(), # 单选 queryset=models.Publisher.objects.all() # 单选这个是和你模型绑定 ) authors = forms.ModelMultipleChoiceField( # choices=models.Author.objects.all().values_list("id", "name"), # widget=forms.widgets.SelectMultiple(), # 多选 queryset=models.Author.objects.all() # 单选这个是和你模型绑定 )
form组件中遇到的知识点:
用form组件实现增改查 1. 在页面展示html时 {% for filed in form_obj %} <p> {{ filed.label }} {{ filed }} </p> {% endfor %} 2. ChoiceField -> ModelChoiceField -> ModelMultipleChoiceField 1. ModelChoiceField 生成select标签 option选项是从queryset中获取的 2. ModelMultipleChoiceField 生成多选的select标签 option选项是从queryset中获取 3. form_obj如何设置初始化的值 from django.forms.models import model_to_dict --> Django 内置的把ORM对象转换成字典的工具函数 obj_dict = model_to_dict(book_obj) form_obj = forms.BookForm(initial=obj_dict)
3.使用modelform,使用这个简单明了,就是在form.py写:
from django import forms from app01 import models class BookForm(forms.Form): title = forms.CharField(max_length=32, label="书名") price = forms.DecimalField(max_digits=5, decimal_places=2) publish_date = forms.DateField( # 这个是因为返回的页面要是date格式的 widget=forms.widgets.DateInput( attrs={"type": "date"} ) ) publisher = forms.ModelChoiceField( # choices=models.Publisher.objects.all().values_list("id","name"), # widget=forms.widgets.Select(), # 单选 queryset=models.Publisher.objects.all() # 单选这个是和你模型绑定 ) authors = forms.ModelMultipleChoiceField( # choices=models.Author.objects.all().values_list("id", "name"), # widget=forms.widgets.SelectMultiple(), # 多选 queryset=models.Author.objects.all() # 单选这个是和你模型绑定 ) # modelform 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": "价格" }
views.py代码:
# y用modelform的增加书籍 def add_book2(request): # 获取前端提交的数据 if request.method == "POST": # 不用一步一步写了,直接获取就行了 form_obj = forms.BookModelForm(request.POST) # 进行校验 if form_obj.is_valid(): form_obj.save() return redirect("/book_list/") form_obj = forms.BookModelForm() return render(request, "add_book1.html", locals()) # y用modelform的编辑书籍 def edit_book2(request, pk): book_obj = models.Book.objects.filter(id=pk).first() if request.method == "POST": form_obj = forms.BookModelForm(request.POST, instance=book_obj) if form_obj.is_valid(): form_obj.save() return redirect("/book_list/") form_obj = forms.BookModelForm(instance=book_obj) # 实例:直接传,不需要转成字典类型 return render(request, "edit_book1.html", locals())