ModelForm组件

Form组件

Model进阶

什么是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>

  

 具体详见:博客一博客二

 

posted @ 2020-05-15 20:27  zh_小猿  阅读(282)  评论(0编辑  收藏  举报