Django之ModelForm

12345huangchun 2019-01-16 原文

Django之ModelForm

  在前面有篇博客,我写了一个叫forms组件的东西,可以帮助我们完成校验数据、渲染标签功能和在前端页面局部刷新功能,功能封装的已经很好了,当时已经很开心了。但万万没想到,还有比它功能更强大的东西。forms组件只能渲染出type=text类型的标签,而且还要我们写无数多个字段,然后跟上校验条件,用forms组件做编辑页面时,还要手动的把编辑的对象的每一个值写入标签的value,这些等等虽然相较没用forms组件之前更方便了,但跟ModelForm比起来,都显得苍白无力,把ModelForm吹了那么久,现在就让我们来见识见识ModelForm的强大。

  不管是用什么,首先都得有模型类吧,创建模型类是没有变化的,这是往库里创建表的必有步骤,肯定是变不的。

  一、创建模型类,完成数据库迁移

  models.py

from django.db import models

# Create your models here.
class Book(models.Model):
    name=models.CharField(max_length=15,verbose_name='名字')
    price=models.IntegerField(verbose_name='价格')
    pub_date=models.DateTimeField(verbose_name='出版时间')
    publish = models.ForeignKey('Publish', on_delete=models.CASCADE,verbose_name='出版社')
    author=models.ManyToManyField('Author',db_table='book_author',verbose_name='作者')
    class Meta:
        db_table='Book'
        verbose_name='书籍'
    def __str__(self):
        return self.name
class Publish(models.Model):
    name=models.CharField(max_length=15,verbose_name='名字')
    addr=models.CharField(max_length=15,verbose_name='地址')
    phone=models.IntegerField(verbose_name='电话号码')
    class Meta:
        db_table='Publish'
        verbose_name='出版社'
    def __str__(self):
        return self.name
class Author(models.Model):
    name=models.CharField(max_length=15,verbose_name='名字')
    age=models.IntegerField(verbose_name='年龄')
    author_info=models.OneToOneField('Author_Info',on_delete=models.CASCADE,verbose_name='详情')
    class Meta:
        db_table='Author'
        verbose_name='作者'
    def __str__(self):
        return self.name
class Author_Info(models.Model):
    gf_name=models.CharField(max_length=10,verbose_name='女朋友名字')
    telephone=models.IntegerField(verbose_name='电话号码')
    ShenFenZheng=models.IntegerField(verbose_name='身份证号')
    class Meta:
        db_table='Author_Info'
        verbose_name='作者详情'
    def __str__(self):
        return str(self.ShenFenZheng)

  二、创建一个ModelForm类

from django import forms
from  django.forms import widgets as wid
class BookModelForm(forms.ModelForm):
    class Meta:
        model=models.Book             #这相当于给Book模型类创建的
        # fields=["title","price"]
        # exclude = ["title"]
        fields="__all__"             #这是要校验的字段,现在表示所有字段校验,上面两种写法也可以。

        widgets={
            "name":wid.TextInput(attrs={"class":"form-control"}),
            "price":wid.TextInput(attrs={"class":"form-control"})
        }                           #这是对用ModelForm生成标签的属性修改
        error_messages={
            "name":{"required":"该字段不能为空"}
        }                          #这是修改错误信息的显示样式
        labels={
            "name":"书籍名称"
        }

    def  clean_title(self):       #也可以定义钩子
        val=self.cleaned_data.get("title")
        if val.startswith("xxx"):
            return val
        else:
            raise  ValidationError("必须以xxx开头!")

  ModelForm校验数据和forms组件是一样,用is_valid()按照校验规则来校验,错误的信息会放在form.errors里面。

  三、渲染标签

  views.py

def addbook(request):
    if request.method=="POST":
        form=BookModelForm(request.POST)
        if form.is_valid():
            form.save()           #当数据校验通过后,我们不用写什么create,只需要写上这一句,就完成在表中创建一条记录。
            return redirect("/books/")
        else:
            return render(request, 'addbook.html', locals())
    else:

        # form=BookForm()   # forms组件
        form=BookModelForm()       #  modelforms组件
        return render(request,'addbook.html',locals())

  add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.css">
    <script src="/static/jquery-3.3.1.js"></script>
    <script src="/static/js/bootstrap.js"></script>
    <style>
        .outer{
            margin-top: 200px;
        }
        .title{
            margin-bottom: 50px;
        }
        ul{
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .left{
            position: fixed;
            left: 0;
            top: 20px;
        }
    </style>
</head>
<body>
    <div class="left">
        <div class="panel panel-primary">
            <div class="panel-heading">
                <h3 class="panel-title">操作栏</h3>
            </div>
            <div class="panel-body">
                <div>
                    <a href="{% url 'app01_publish_add' %}?next={{ url }}" class="">添加出版社</a>
                </div>
                <div>
                    <a href="" class="">添加作者</a>
                </div>
            </div>
        </div>
    </div>
    <div class="container outer">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <div style="color: blue;font-size: 50px;text-align: center;font-family: 华文隶书" class="title">添加{{ zw_name }}</div>
                <form action="" method="post" novalidate>
                    {% csrf_token %}
                    {% for field in form %}
                        <div class="form-group ">
                            <label for="id_{{ field.name }}">{{ field.label }}</label>
                            {{ field }}<span style="color: red">{{field.errors }}</span>
                        </div>
                    {% endfor %}
                    <button class="submit btn btn-info pull-right">提交</button>
                </form>
            </div>
        </div>
    </div>
    <script>
    $('input,select').addClass('form-control');
    </script>
</body>
</html>

  其实从代码层面上讲,做add校验和标签渲染没多大区别,但在前端页面上看是有区别的,forms组件只能渲染成type=text的input标签,多于一对多和多对多的字段就无能为力了,还得自己去写。但ModelForm就不一样了,它会把你的一对多的字段渲染成单选的select标签,把多对多的字段渲染成多选的select标签,这样就相当方便了。如下图:

  ModelForm可以渲染select标签,它在编辑页面还有更强大的功能,你只需把一个模型类的对象传给他,他就可以帮你把对象每个值取出来,然后赋予标签的value,在更新数据时也不用写update了,用save()就搞定了。这就解决了我们要手动的去把要编辑的对象每个字段的值取出来放入标签中。

  views.py

def editbook(request,edit_book_id):
    edit_book = models.Book.objects.filter(pk=edit_book_id).first()
    if request.method=="POST":
        form = BookModelForm(request.POST,instance=edit_book)
        if form.is_valid():
            form.save()       #在这里用save()的前提是校验的时候你把要编辑的对象传给ModelForm的instance参数了,不然就相当于重新创建一条表记录
            return redirect("/books/")
        else:
            return render(request, 'editbook.html', locals())
    else:
        form=BookModelForm(instance=edit_book)     #要把编辑的对象传给ModelForm的instance参数
        return render(request,'editbook.html',locals())

  edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.css">
    <script src="/static/jquery-3.3.1.js"></script>
    <script src="/static/js/bootstrap.js"></script>
    <style>
        .outer{
            margin-top: 200px;
        }
        .title{
            margin-bottom: 50px;
        }
        ul{
            list-style: none;
            margin: 0;
            padding: 0;
        }
        .left{
            position: fixed;
            left: 0;
            top: 20px;
        }
    </style>
</head>
<body>
    <div class="left">
        <div class="panel panel-primary">
            <div class="panel-heading">
                <h3 class="panel-title">操作栏</h3>
            </div>
            <div class="panel-body">
                <div>
                    <a href="{% url 'app01_publish_add' %}?next={{ url }}" class="">添加出版社</a>
                </div>
                <div>
                    <a href="" class="">添加作者</a>
                </div>
            </div>
        </div>
    </div>
    <div class="container outer">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <div style="color: blue;font-size: 50px;text-align: center;font-family: 华文隶书" class="title">编辑{{ zw_name }}</div>
                <form action="" method="post" novalidate>
                    {% csrf_token %}
                    {% for field in form %}
                        <div class="form-group ">
                            <label for="id_{{ field.name }}">{{ field.label }}</label>
                            {{ field }}<span style="color: red">{{field.errors }}</span>
                        </div>
                    {% endfor %}
                    <button class="submit btn btn-info pull-right">提交</button>
                </form>
            </div>
        </div>
    </div>
    <script>
    $('input,select').addClass('form-control');
    </script>
</body>
</html>

 

  结果:

 

   总之啊,ModelForm是相当的好用,一直以来,我的叫法应该都有问题,我一直把forms组件下的Form叫成forms组件,之前写的Form和今天写的ModelForm都属于forms组件,大家请原谅我。

发表于 2019-01-16 21:23 W的一天 阅读() 评论() 编辑 收藏

 

版权声明:本文为12345huangchun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/12345huangchun/p/10279483.html

Django之ModelForm的更多相关文章

随机推荐

  1. flink入门到实战(4)flink基础篇

    Flink面试–核心概念和基础考察 1、简单介绍一下 Flink 2、Flink 相比传统的 Sp […]...

  2. 未来十年Python的前景会怎样?

    转自:一位非常优秀的Python倡导者 作者:alex链接:https://www.zhihu.com/que […]...

  3. 如何查看笔记本装的什么硬盘?

    如何查看笔记本装的什么硬盘? 1. win10系统搜索Powershell   2.以管理员身份运行     […]...

  4. TensorFlow tf.gradients的用法详细解析以及具体例子

    tf.gradients 官方定义: tf.gradients( ys, xs, grad_ys=None, […]...

  5. 示波器基础知识

      为保证波形不失真,考虑按基波幅度的10%以上谐波为影响波形的重要因素选择示波器带宽。(在复杂的周期性振荡中 […]...

  6. javac不是内部或外部命令在win10上的解决方案

    Path环境变量能够让你在任何路径都能使用命令,可能你百度谷歌了各种方案都无法解决javac无法使用的问题,那 […]...

  7. 原型工具介绍———墨刀以及Axure RP比较

    原型工具——墨刀以及Axure的比较   1759233     目录 一.了解背景… 1 二.下 […]...

  8. .net core实践系列之短信服务-Sikiro.SMS.Job服务的实现

    前言 本篇会继续讲解Sikiro.SMS.Job服务的实现,在我写第一篇的时候,我就发现我当时设计的架构里Si […]...

展开目录

目录导航