zoukankan      html  css  js  c++  java
  • python之路_django ModelForm组件

      在前面我们介绍了过django的forms组件,他可以很方便的实现我们前端的input框渲染和数据校验,但是我们使用过会发现,models组件在定义的时候我们需要定义相应的一些字段内容,但是有时候页面的表单form类与Model类是一一对应,因此分别定义Form类和Model类会比较麻烦,最简单的方式就是通过Model来生成一个Form类,因此,Django内置的ModelForm就是为此而生的.

    一、ModelForm类的定义

    如下我们定义了个modelform类:

    from .models import *
    from django.forms import ModelForm
    from django.forms import widgets
    class BookForm(ModelForm):
        class Meta:
            model=Book
            fields=["title","publishDate","price","publish","authors"]
            widgets={
                "title":widgets.TextInput(attrs={"class":"form-control"}),
                # "publishDate":widgets.DateInput(attrs={"class":"form-control"}),
                "publishDate":widgets.TextInput(attrs={"class":"form-control","type":"Date"}),
                "price":widgets.TextInput(attrs={"class":"form-control"}),
                "publish":widgets.Select(attrs={"class":"form-control"}),
                "authors":widgets.SelectMultiple(attrs={"class":"form-control"})
            }

     model 文件:

    from django.db import models
    
    class Book(models.Model):
        nid=models.AutoField(primary_key=True)
        title=models.CharField(max_length=32,verbose_name="书名")
        publishDate=models.DateField(verbose_name="出版日期")
        price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")
        publish=models.ForeignKey("Publish",verbose_name="出版社")      #与Publish表建立多对一关系
        authors=models.ManyToManyField("Author",verbose_name="作者")    #与Author表建立多对多关系
    
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        nid=models.AutoField(primary_key=True)
        name=models.CharField(max_length=32)
        email=models.EmailField()
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid=models.AutoField(primary_key=True)
        name=models.CharField(max_length=32)
        age=models.IntegerField()
    
        def __str__(self):
            return self.name

    说明一:  

      (1)引入方式:from django.forms import ModelForm;

      (2)model=Book:Book为model中Book类;

      (3)fields=["title","publishDate","price","publish","authors"]:指定BookForm类中需要Book中字段,若fields="__all__"表示将取Book类中的所有字段;

      (4)widgets:通过它补充定义相应字段在渲染出来的input标签的类型,并可以给他传一些属性。

    说明二:

      上述两个字段在我们Book类中是两个关联字段,分别是多对一和多对多关系,即一本书只能有一个出版社,但是有多个作者,所以对于我们将其标签类型设置为select和selectMultiple,modelform的牛逼之一就是:在页面渲染此两个标签时,不但会渲染出单选框和多选框,还能自动查询Publish和Author表,将相应的已有的对象数据渲染,供用户选择。

    说明三:

      另外一点,对于日期字段,无论我们将标签设置成何种类型(DateInput还是TextInput),我们看到的还是一个需要我们自己输入内容的输入框,但是如何渲染出我们可以选年月日的哪一种呢?如上,需要我们设置type:Date属性。

    说明四:

      如上我们定义的modelform类,我们也可以像form组件一样,继续在modelform类下定义局部钩子和全局钩子,进一步对字段做约束,方便校验。

    二、ModelForm类的使用

    1、添加书籍实例

      视图函数:

    def addbook(request):
        if request.method=="POST":
            bookForm = BookForm(data=request.POST)
            if bookForm.is_valid():
                bookForm.save()  #save方法直接将接收的数据作为一条新数据添加
                return redirect("/index/")
            else:
                pass
        else:
            bookForm=BookForm()
            return render(request,"add_book.html",locals())

      add_book.html:

    方式一:

    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <form action="/add_book/" method="post">
                    {% csrf_token %}
                    {% for foo in book_form %}
                        <p>
                            <label for="">{{ foo.label }}</label>
                            {{ foo }}
                        </p>
                    {% endfor %}
                    <input type="submit" value="submit">
                </form>
    
            </div>
        </div>
    </div>

      如上实例,我们在前端页面直接可以对服务器传来的modelform类实例化的对象进行循环,循环的每一个foo对象就会按照按照顺序渲染出相应字段的输入标签,但是和form组件一样,form标签和submit标签需要我们事先定义。注意一点:通过如上<label for="">{{ foo.label }}</label>可以渲染出foo对应字段中定义的verbose_name值,作为label标签的名称。如若foo对应的是title=models.CharField(max_length=32,verbose_name="书名")字段,则会渲染出相应的label标签<label for="">书名</label>

      显然一点,上述通过循环的方式,按照顺序的方式渲染对应的字段输入标签显然不是很灵活,我们是否有其他的办法来解决这个问题呢?必须的有啊。通过实例化的modelform对象直接取自己包含的字段名,就可以渲染出相应的输入标签。具体实例如下:

    方式二:

    <form class="form-horizontal" action="/addbook/" method="post">
        {% csrf_token %}
         <div class="form-group">
                <label for="" class="col-sm-2 control-label">{{ bookForm.title.label }}</label>
                <div class="col-sm-6">
                    {{ bookForm.title }}
                </div>
         </div>
        <div class="form-group">
                <label for="" class="col-sm-2 control-label">{{ bookForm.price.label }}</label>
                <div class="col-sm-6">
                    {{ bookForm.price }}
                </div>
        </div>
        <div class="form-group">
            <label for="" class="col-sm-2 control-label">{{ bookForm.publishDate.label }}</label>
            <div class="col-sm-6">
                {{ bookForm.publishDate }}
            </div>
        </div>
        <div class="form-group">
            <label for="" class="col-sm-2 control-label">{{ bookForm.publish.label }}</label>
            <div class="col-sm-6">
                {{ bookForm.publish }}
            </div>
        </div>
        <div class="form-group">
            <label for="" class="col-sm-2 control-label">{{ bookForm.authors.label }}</label>
            <div class="col-sm-6">
                {{ bookForm.authors }}
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-6">
                <button type="submit" class="btn btn-success btn-lg center-block">提交</button>
            </div>
        </div>
    </form>

    2、编辑书籍实例

      视图函数:

    def editbook(request,id):
        book_obj=Book.objects.get(nid=id)
        if request.method=="POST":
            bookForm = BookForm(data=request.POST,instance=book_obj)
            if bookForm.is_valid():
                bookForm .save()
                return redirect("/index/")
        else:
            bookForm = BookForm(instance=book_obj)
            return render(request,"edit_book.html",locals())

      我们知道,编辑一条信息和添加一条信息的不同在于,不论在渲染页面还是保存编辑后的数据,我们都需要知道是在对那一条数据进行编辑,因此在渲染编辑页面时,我们不但要渲染出相应字段的输入标签,还要渲染出各字段编辑前的数据,所以用于渲染页面的mdelform实例对象必须要有个instance参数,参数值为当前要编辑的数据对象。编辑完成后,服务器在进行数据保存时同样也要有这样的一个参数。具体见如上实例。

  • 相关阅读:
    [单链表]链表指针追赶问题
    二叉查找树与平衡二叉树
    二叉树的下一个结点
    fork进程函数总结
    《Effective C++》Item2:尽量以const,enum,inline替换#define
    Hash表的使用
    [数字]整数数字的算法
    算法题:找出整数数组中两个只出现一次的数字
    删除元素的操作
    [Reprinted] 使用Spring Data Redis操作Redis(一) 很全面
  • 原文地址:https://www.cnblogs.com/seven-007/p/8186015.html
Copyright © 2011-2022 走看看