Django之modelform组件

modelform来源:

  构建一个数据库驱动的应用,那么你可能会有与Django的模型紧密映射的表单。比如,你有个Student模型,并且你还想创建一个表单让大家提交评论到这个模型中。在这种情况下,写一个forms.Form类,然后在表单类中定义字段,这种一般创建表单的做法是冗余的,因为你已经在ORM模型model中定义了字段的属性和功能,完全没必要重新写一遍字段。

一、核心用法

基于这个原因,Django提供一个辅助类帮助我们利用Django的ORM模型model创建Form。

用法的核心是:

1.首先从django.forms导入ModelForm;
2.编写一个自己的类,继承ModelForm;
3.在新类里,设置元类Meta;
4.在Meta中,设置model属性为你要关联的ORM模型,这里是Article;
5.在Meta中,设置fields属性为你要在表单中使用的字段列表;
6.列表里的值,应该是ORM模型model中的字段名。

上面的例子中,因为model和form比较简单,字段数量少,看不出这么做的威力和效率。但如果是那种大型项目,每个模型的字段数量几十上百,这么做的收益将非常巨大,而且后面还有一招提高效率的大杀器,也就是一步保存数据的操作。

 

Django在设计model字段和表单字段时存在大量的相似和重复之处。

特别注意:ManyToManyField和 ForeignKey字段类型属于特殊情况:

  • ForeignKey被映射成为表单类的django.forms.ModelChoiceField,它的选项是一个模型的QuerySet,也就是可以选择的对象的列表,但是只能选择一个。

  • ManyToManyField被映射成为表单类的django.forms.ModelMultipleChoiceField,它的选项也是一个模型的QuerySet,也就是可以选择的对象的列表,但是可以同时选择多个,多对多嘛。

同时,在表单属性设置上,还有下面的映射关系:

如果模型字段设置blank=True,那么表单字段的required设置为False。 否则,required=True。
表单字段的label属性根据模型字段的verbose_name属性设置,并将第一个字母大写。
如果模型的某个字段设置了editable=False属性,那么它表单类中将不会出现该字段。道理很简单,都不能编辑了,还放在表单里提交什么?
表单字段的help_text设置为模型字段的help_text。
如果模型字段设置了choices参数,那么表单字段的widget属性将设置成Select框,其选项来自模型字段的choices。
选单中通常会包含一个空选项,并且作为默认选择。如果该字段是必选的,它会强制用户选择一个选项。 如果模型字段具有default参数,则不会添加空选项到选单中。

以下是使用modelform的示例,详细看代码:

models:

from django.db import models

# Create your models here.
class Book(models.Model):
    id = models.AutoField(primary_key=True) #可不填,Django会自动帮你写
    title = models.CharField(max_length=32,)
    price = models.DecimalField(max_digits=5, decimal_places=2,)
    pub_date = models.DateField()
    #与Publish(id)建立一对多的外键关系
    publish = models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    # 不会添加外键,会另外创建表格
    authors = models.ManyToManyField(to="Author")
    def __str__(self):
        return self.title

    class Meta:
        verbose_name="书籍"

class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()
    def __str__(self):
        return self.name

    class Meta:
        verbose_name="出版社"

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    authorDetail = models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
    def __str__(self):
        return self.name
    class Meta:
        verbose_name = "作者"

class AuthorDetail(models.Model):
    birthday = models.DateField()
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)
    def __str__(self):
        return self.addr

    class Meta:
        verbose_name = "作者详情"

class user_info(models.Model):
    name = models.CharField(max_length=64)
    password = models.CharField(max_length=64)
    def __str__(self):
        return self.name
View Code

views:

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms import widgets as wid
from django import forms


class BookModelForm(forms.ModelForm):
    class Meta:
        model = models.Book  #绑定对应的模型
        # fields=["title","price"]
        # exclude = ["title"]
        fields = "__all__"  #自定义要展示的字段

        widgets = {   #自定义字段的样式
            "title": wid.TextInput(attrs={"class": "form-control"}),
            "price": wid.TextInput(attrs={"class": "form-control"}),
            "pub_date":wid.TextInput(attrs={"class": "form-control"}),
            "publish": wid.Select(attrs={"class": "form-control"}),
            "authors": wid.SelectMultiple(attrs={"class": "form-control"}),

        }

        error_messages = {
            "title": {"required": "该字段不能为空"}  #自定义错误信息
        }
        labels = {
            "title": "书籍名称"                  #自定义字段名称,展示起来比较素福
        }
    #
    def clean_title(self):
        val = self.cleaned_data.get("title")
        if val.startswith("a"):
            return val
        else:
            raise ValidationError("必须以a开头!")


def addbook(request):
    if request.method == "POST":
        form = BookModelForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("/books/")
        else:
            return render(request, 'addbook.html', locals())
    else:
        form = BookModelForm()  # modelforms组件
        return render(request, 'addbook.html', locals())
View Code

 html:

<div class="row">
    <div class="col-md-4 col-md-offset-3">
        <form action="" method="post" novalidate>
            {% csrf_token %}
            {% for field in form %}
                <div class="form-group">
                    <label for="title">{{ field.label }}</label>
                    {{ field }} <span>{{ field.errors.0 }}</span>
                </div>
             {% endfor %}

            <input type="submit"value="submit" class="btn btn-default pull-right">
        </form>
    </div>
</div>
View Code

 

详细可参考:http://www.liujiangblog.com/course/django/156

或有关BaseModelform的相关参数可参考:https://blog.csdn.net/russell_tao/article/details/52777302

 

posted @ 2019-03-07 22:02  Mixtea  阅读(265)  评论(0编辑  收藏  举报