文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Django之ModelForm

2023-01-30 23:27

关注

  在前面有篇博客,我写了一个叫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组件,大家请原谅我。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯