Django ModelForm组件使用方法详解


Posted in Python onJuly 23, 2019

一、创建ModelForm

from django.forms import ModelForm
from appxx import models
from django.forms import widgets as wdt # 因为重名,所以起个别名
#定义一个类,比如BookForm,这个类要继承ModelForm,在这个类中再写一个原类Meta(规定写法,注意首字母是大写的)
#在这个原类中,有以下属性(部分):
class BookForm(ModelForm):
  class Meta:
    model = models.Book # 对应的Model中的类
    fields = "__all__" # 字段,如果是__all__,就表示列出所有的字段,或者使用列表列出想要的字段
    exclude = None # 排除的字段
    # error_messages用法
    error_messages = {
      "title": {"required": "书名不能为空"},
      "price": {"required": "售价不能为空"},
    }
    # widgets用法,比如把输入用户名的input框给为Textarea
    widgets = {
      "name": wdt.Textarea(attrs={"class": "c1"}) # 还可以自定义属性
    }
    #labels,自定义在前端显示的名字
    labels= {
      "title": "书名",
      "price": "售价",
    }

然后在 url 对应的视图函数中实例化这个类,把这个对象传给前端:

def add_book(request):
  form = forms.BookForm()
  return render(request, "add_book.html", {"form": form})

然后在前端像Form组件那样渲染页面

二、添加数据

保存数据的时候,不用挨个取数据了,只需要 save 一下即可。

from django.shortcuts import render,redirect
from appxx import models
from appxx import forms


def add_book(request):
  if request.method == "POST":
    form = forms.BookForm(request.POST)
    if form.is_valid():
      form.save()
      return redirect("/book/")
  form = forms.BookForm()
  return render(request, "add_book.html", {"form": form})

三、编辑数据

如果不使用 ModelForm,编辑的时候得显示之前的数据,还得挨个取一遍值;如果使用 ModelForm,只需要加一个instance=obj(obj是要修改的数据库的一条数据的对象)就可以得到同样的效果。

保存的时候要注意,一定要注意有这个对象(instance=obj),否则不知道更新哪一个数据。

from django.shortcuts import render,redirect
from appxx import models
from appxx import forms


def edit_book(request, edit_book_id):
  edit_book= models.Book.objects.filter(id=edit_book_id).first()
  if request.method == "POST":
    form = forms.BookForm(request.POST, instance=edit_book)
    if form.is_valid():
      form.save()
      return redirect("/book/")
  form = forms.BookForm(instance=edit_book)
  return render(request, "edit_book.html", {"form": form})

总结: 从上边可以看到 ModelForm 用起来是非常方便的,比如增加修改之类的操作。但是也带来额外不好的地方,model和form之间耦合了。如果不耦合的话,form.save()方法也无法直接提交保存。 但是耦合的话使用场景通常局限用于小程序,写大程序就最好不用了。

四、完整示例代码

项目结构

Django ModelForm组件使用方法详解

urls.py

from django.conf.urls import url
from django.contrib import admin
from appxx import views


urlpatterns = [
  url(r'^admin/', admin.site.urls),
  url(r"^book/$", views.book),
  url(r"^book/add/", views.add_book),
  url(r"^book/edit/(\d+)/", views.edit_book),
]

views.py

from django.shortcuts import render,redirect
from appxx import models
from appxx import forms


def book(request):
  book_list = models.Book.objects.all()
  return render(request, "book.html", {"book_list": book_list})


def add_book(request):
  if request.method == "POST":
    form = forms.BookForm(request.POST)
    if form.is_valid():
      form.save()
      return redirect("/book/")
  form = forms.BookForm()
  return render(request, "add_book.html", {"form": form})


def edit_book(request, edit_book_id):
  edit_book= models.Book.objects.filter(id=edit_book_id).first()
  if request.method == "POST":
    form = forms.BookForm(request.POST, instance=edit_book)
    if form.is_valid():
      form.save()
      return redirect("/book/")
  form = forms.BookForm(instance=edit_book)
  return render(request, "edit_book.html", {"form": form})

models.py

from django.db import models


class Book(models.Model):
  id = models.AutoField(primary_key=True)
  title = models.CharField(max_length=32)
  price = models.DecimalField(max_digits=5, decimal_places=2)
  publish_date = models.DateField()
  publisher = models.ForeignKey(to="Publisher")
  authors = models.ManyToManyField(to="Author")

  def __str__(self):
    return self.title


class Publisher(models.Model):
  id = models.AutoField(primary_key=True)
  name = models.CharField(max_length=32)

  def __str__(self):
    return self.name


class Author(models.Model):
  id = models.AutoField(primary_key=True)
  name = models.CharField(max_length=32)

  def __str__(self):
    return self.name

forms.py

from django.forms import ModelForm
from appxx import models
from django.forms import widgets as wdt


class BookForm(ModelForm):
  class Meta:
    model = models.Book
    fields = "__all__"
    labels = {
      "title": "书名",
      "price": "售价",
      "publish_date": "出版日期",
      "publisher": "出版社",
      "authors": "作者"
    }
    widgets = {
      "title": wdt.TextInput(attrs={"class": "form-control"}),
      "price": wdt.TextInput(attrs={"class": "form-control"}),
      "publish_date": wdt.TextInput(attrs={"class": "form-control", "type": "date"}),
      "publisher": wdt.Select(attrs={"class": "form-control"}),
      "authors": wdt.SelectMultiple(attrs={"class": "form-control"}),

    }
    error_messages = {
      "title": {"required": "书名不能为空"},
      "price": {"required": "售价不能为空"},
      "publish_date": {"required": "出版日期不能为空"},
      "publisher": {"required": "出版社不能为空"},
      "authors": {"required": "作者不能为空"},
    }

book.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <title>展示书籍</title>
  <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" >
</head>
<body>
<div class="container">
  <div class="row">
    <div class="col-md-6 col-md-offset-3">
      <span><a class="btn btn-primary" href="/book/add/" rel="external nofollow" >添加</a></span>
      <table class="table table-striped table-bordered">
        <thead>
        <tr>
          <th>序号</th>
          <th>书名</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.title }}</td>
            <td>{{ book.price }}</td>
            <td>{{ book.publish_date }}</td>
            <td>{{ book.publisher.name }}</td>
            <td>
              {% for author in book.authors.all %}
                {{ author.name }}
              {% endfor %}
            </td>
            <td>
              <span><a class="btn btn-warning" href="/book/edit/{{ book.pk }}/" rel="external nofollow" >编辑</a></span>
              <span><a class="btn btn-danger" href="">删除</a></span>
            </td>
          </tr>
        {% endfor %}
        </tbody>
      </table>
    </div>
  </div>
</div>
</body>
</html>

add_book.html和edit_book.html(两个页面代码一样)

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <title>添加书籍</title>
  <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" >
  <style>
    .panel-title {
      font-weight: bolder;
    }

    .panel {
      margin-top: 30px;
    }
  </style>
</head>
<body>
<div class="container">
  <div class="row">
    {# panel开始 #}
    <div class="panel panel-danger col-sm-6 col-md-6 col-sm-offset-3 col-md-offset-3">
      <div class="panel-heading">
        <h3 class="panel-title">添加书籍</h3>
      </div>
      {# panel-body开始 #}
      <div class="panel-body">
        {# form开始 #}
        <form class="form-horizontal" action="" method="post" novalidate>
          {% csrf_token %}
          <div class="form-group">
            <label class="col-md-2 control-label"
                for="{{ form.title.id_for_label }}">{{ form.title.label }}</label>
            <div class="col-md-10">
              {{ form.title }}
            </div>
          </div>
          <div class="form-group">
            <label class="col-md-2 control-label"
                for="{{ form.price.id_for_label }}">{{ form.price.label }}</label>
            <div class="col-md-10">
              {{ form.price }}
            </div>
          </div>
          <div class="form-group">
            <label class="col-md-2 control-label"
                for="{{ form.publish_date.id_for_label }}">{{ form.publish_date.label }}</label>
            <div class="col-md-10">
              {{ form.publish_date }}
            </div>
          </div>
          <div class="form-group">
            <label class="col-md-2 control-label"
                for="{{ form.publisher.id_for_label }}">{{ form.publisher.label }}</label>
            <div class="col-md-10">
              {{ form.publisher }}
            </div>
          </div>
          <div class="form-group">
            <label class="col-md-2 control-label"
                for="{{ form.authors.id_for_label }}">{{ form.authors.label }}</label>
            <div class="col-md-10">
              {{ form.authors }}
            </div>
          </div>
          <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
              <button type="submit" class="btn btn-success">提交</button>
              <a class="btn btn-warning pull-right" href="/book/" rel="external nofollow" >取消</a>
            </div>
          </div>
        </form>
        {# form结束 #}
      </div>
      {# panel-body结束 #}
    </div>
    {# panel结束 #}
  </div>
</div>
</body>
</html>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
动感网页相册 python编写简单文件夹内图片浏览工具
Aug 17 Python
详解Python中 sys.argv[]的用法简明解释
Dec 20 Python
Python3 queue队列模块详细介绍
Jan 05 Python
Python使用Windows API创建窗口示例【基于win32gui模块】
May 09 Python
使用pandas模块读取csv文件和excel表格,并用matplotlib画图的方法
Jun 22 Python
基于Python实现船舶的MMSI的获取(推荐)
Oct 21 Python
基于pytorch的lstm参数使用详解
Jan 14 Python
Django添加bootstrap框架时无法加载静态文件的解决方式
Mar 27 Python
python读取excel数据绘制简单曲线图的完整步骤记录
Oct 30 Python
python 爬虫爬取京东ps4售卖情况
Dec 18 Python
[原创]赚疯了!转手立赚800+?大佬的python「抢茅台脚本」使用教程
Jan 12 Python
python 中 .py文件 转 .pyd文件的操作
Mar 04 Python
Pandas之groupby( )用法笔记小结
Jul 23 #Python
Python OpenCV调用摄像头检测人脸并截图
Aug 20 #Python
使用PYTHON解析Wireshark的PCAP文件方法
Jul 23 #Python
Django 静态文件配置过程详解
Jul 23 #Python
python 设置xlabel,ylabel 坐标轴字体大小,字体类型
Jul 23 #Python
pandas通过字典生成dataframe的方法步骤
Jul 23 #Python
Python基于OpenCV实现人脸检测并保存
Jul 23 #Python
You might like
php入门教程 精简版
2009/12/13 PHP
一些被忽视的PHP函数(简单整理)
2010/04/30 PHP
mysqli_set_charset和SET NAMES使用抉择及优劣分析
2013/01/13 PHP
ThinkPHP之M方法实例详解
2014/06/20 PHP
PHP实现登录注册之BootStrap表单功能
2017/09/03 PHP
PHP number_format函数原理及实例解析
2020/07/14 PHP
SOSO地图API使用(一)在地图上画圆实现思路与代码
2013/01/15 Javascript
js 程序执行与顺序实现详解
2013/05/13 Javascript
Javascript添加监听与删除监听用法详解
2014/12/19 Javascript
Nodejs学习笔记之Global Objects全局对象
2015/01/13 NodeJs
JavaScript插件化开发教程 (三)
2015/01/27 Javascript
JS实现的5级联动Select下拉选择框实例
2015/08/17 Javascript
jquery插件格式实例分析
2016/06/16 Javascript
node通过npm写一个cli命令行工具
2017/10/12 Javascript
详解如何使用koa实现socket.io官网的例子
2018/11/04 Javascript
微信小程序如何引用外部js,外部样式,公共页面模板
2019/07/23 Javascript
JS实现炫酷轮播图
2020/11/15 Javascript
[02:22]《新闻直播间》2017年08月14日
2017/08/15 DOTA
Python Deque 模块使用详解
2014/07/04 Python
Python中实现的RC4算法
2015/02/14 Python
Python判断telnet通不通的实例
2019/01/26 Python
详解Django-restframework 之频率源码分析
2019/02/27 Python
Python函数定义及传参方式详解(4种)
2019/03/18 Python
Python用字典构建多级菜单功能
2019/07/11 Python
解决python明明pip安装成功却找不到包的问题
2019/08/28 Python
python动态视频下载器的实现方法
2019/09/16 Python
基于K.image_data_format() == 'channels_first' 的理解
2020/06/29 Python
美国体育用品商店:Academy Sports + Outdoors
2020/01/04 全球购物
函授生自我鉴定
2014/03/25 职场文书
平安家庭示范户事迹
2014/06/02 职场文书
优秀班主任推荐材料
2014/12/17 职场文书
感恩教育观后感
2015/06/17 职场文书
教师个人教学反思
2016/02/23 职场文书
mysql批量新增和存储的方法实例
2021/04/07 MySQL
浅谈node.js中间件有哪些类型
2021/04/29 Javascript
教你用Java Swing实现自助取款机系统
2021/06/11 Java/Android