forms表单与modelfrom使用

Posted aizhinong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了forms表单与modelfrom使用相关的知识,希望对你有一定的参考价值。

详细参考链接:点击

数据结构models.py

技术图片
from django.db import models

# Create your models here.


class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    date = models.DateField(null=True)
    publish = models.ForeignKey(to=Publish, on_delete=models.CASCADE)
    authors = models.ManyToManyField(Author)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = 书籍表


class Publish(models.Model):
    title = models.CharField(max_length=24)
    site = models.CharField(max_length=80)
    # author = models.

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = 出版社


class Author(models.Model):
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 作者
model.py

在页面上对数据进行操作时,如果不用forms组件,在设计html页面时,会有冗长的代码,特别是修改数据页面,视图中处理数据也同样不方便:

技术图片
      <form action="" method="post" novalidate>
                <div>书名:
                    <input type="text" value="{{ old_book.title }}">
                </div>
                <div>价格:
                    <input type="text" value="{{ old_book.price }}">
                </div>
                <div>时间:
                    <input type="date" value="{{ old_book.date }}">
                </div>
                <div>出版社:
                    <select name="publish" id="">
                        {% for punlish in all_publishs %}
                            {% if old_book.publish == punlish %}
                                <option value="{{ punlish.id }}" selected>{{ punlish.title }}</option>
                            {% else %}
                                <option value="{{ punlish.id }}">{{ punlish.title }}</option>
                            {% endif %}
                        {% endfor %}
                    </select>
                </div>
                <div>作者:
                    <select name="author" id="" multiple>
                        {% for author in all_authors %}
                                {% if author in old_book.authors.all %}
                                    <option value="{{ author.id }}" selected>{{ author.name }}</option>
                                {% else %}
                                    <option value="{{ author.id }}">{{ author.name }}</option>
                                {% endif %}
                            {% endfor %}

                    </select>
                    <input type="submit">
    </form>
</div>
HTML页面冗长的代码
技术图片
def edit_book(request):
    book_forms = forms.AddBook()
    id = request.GET.get(id)
    old_book = models.Book.objects.filter(id=id).first()
    all_publishs = models.Publish.objects.all()
    all_authors = models.Author.objects.all()
    if request.method == POST:
        submit = forms.AddBook(request.POST)
        if submit.is_valid():
            return HttpResponse(ok)

    return render(request, editbook.html,
                  {book_forms: book_forms, old_book: old_book, all_publishs: all_publishs,
                   all_authors: all_authors})
视图函数中冗长的代码

用上modelform组件后:

        {% for fields in book_forms %}
            <div>
                {{ fields.label }}
                {{ fields }} <span style="color: red">{{ fields.errors.0 }}</span>
            </div>
        {% endfor %}
def edit_book(request):
    id = request.GET.get(id)
    old_book = models.Book.objects.filter(id=id).first()
    book_forms = forms.ModelFromBook(instance=old_book)  # modelform接收一个参数instance,为model对象,它自动将这个model对象的值填充到form表单
    if request.method == "POST":
        book_forms = forms.ModelFromBook(request.POST, instance=old_book)
        if book_forms.is_valid():
            book_forms.save()  # 将修改后的值,直接更新
            return redirect(/index/)
        else:
            return render(request, editbook.html, {book_forms: book_forms,})

    return render(request, editbook.html, locals())

 

使用forms组件时需要注意的地方:

技术图片
from django import forms
from django.forms import widgets
from app01 import models


class AddBook(forms.Form):
    title = forms.CharField(max_length=20, min_length=5,
                            error_messages={required: 标题不能为空,
                                            min_length: 标题最少为5个字符,
                                            max_length: 标题最多为20个字符},
                            )
    price = forms.DecimalField(max_digits=8, decimal_places=2)
    date = forms.DateField(
        widget=widgets.TextInput(attrs={type: date})
    )
    publish = forms.ModelChoiceField(queryset=models.Publish.objects.all())  # 单选select框  queryset可以从models表中取queryset对象
    authors = forms.ModelMultipleChoiceField(queryset=models.Author.objects.all())  # 多选select框
forms
技术图片
def add_book(request):
    book_forms = forms.AddBook()
    if request.method == POST:
        book_forms = forms.AddBook(request.POST)
        if book_forms.is_valid():
            title = request.POST.get(title)
            price = request.POST.get(price)
            date = request.POST.get(date)
            publish = request.POST.get(publish)
            authors = request.POST.getlist(authors)
            book_obj = models.Book.objects.create(title=title, price=price, date=date, publish_id=publish)
            book_obj.authors.add(*authors)
            return redirect(/index/)
        else:
            print(book_forms.errors)
            return render(request,addbook.html,{"book_forms": book_forms})

    return render(request, addbook.html, {book_forms: book_forms})
views
技术图片
<div>
    <form action="" method="post" novalidate>
        {% csrf_token %}
        {% for book_form in book_forms %}
            <p>
                {{ book_form.label }}
            {{ book_form }} <span>{{ book_form.errors.0 }}</span>
            </p>

        {% endfor %}
        <input type="submit">
    </form>
</div>
HTML

  1、使用单选与多选框时,queryset参数接收一个queryset对象,可以从models取到。error_messages参数自定义错误提示信息,widgets可以指定input框,并设置样式

  2、提交数据后,视图接收数据,把数据传给forms对象,is_valid方法对数据进行校验,没有错误返回True,之后可以进行数据表操作。有错误返回Flase,errors方法返回所有对应的错误信息的html标签,在模板语言中可以直接通过字段调用错误信息进行渲染,注意需要使用下标获取第一个错误信息

  3、forms的校验方式简洁,但是在校验成功后的数据添加或者更新操作依然麻烦,需要手动的获取每一条数据后,再添加到数据库。modelform很好的解决了这个问题。

 

modelform使用:

技术图片
from django import forms
from django.forms import widgets
from app01 import models

class ModelFromBook(forms.ModelForm):
    class Meta:
        model = models.Book
        fields = __all__  # [‘title‘,‘price‘]
        widgets = {date: forms.widgets.TextInput(attrs={type: date,}),
                   # ‘title‘: forms.widgets.TextInput(attrs={‘class‘: ‘form-control‘}),
                   # ‘price‘: forms.widgets.TextInput(attrs={‘class‘: ‘form-control‘}),
                   # ‘publish‘: forms.widgets.TextInput(attrs={‘class‘: ‘form-control‘}),
                   # ‘authors‘: forms.widgets.TextInput(attrs={‘class‘: ‘form-control‘}),
                   }
        labels = {title: 书名,date: 时间,price: 价格,publish: 出版社,authors:作者}
        error_messages = {title:{required: 书名不能为空},
                          }
modelform
技术图片
# 通过modelform添加数据
def add_book(request):
    book_forms = forms.ModelFromBook()
    if request.method == POST:
        book_forms = forms.ModelFromBook(request.POST)
        if book_forms.is_valid():
            book_forms.save()  # save即可自己添加所有数据
            return redirect(/index/)
        else:
            return render(request,addbook.html,{book_forms:book_forms})

    return render(request, addbook.html, {book_forms: book_forms})
views
技术图片
<div>
    <form action="" method="post" novalidate>
        {% csrf_token %}
        {% for book_form in book_forms %}
            <p>
                {{ book_form.label }}
            {{ book_form }} <span>{{ book_form.errors.0 }}</span>
            </p>

        {% endfor %}
        <input type="submit">
    </form>
</div>
HTML

  1、modelform接收一个参数instance,为model对象,它自动将这个model对象的每个字段值填充到form表单,前端页面的输入框自动将原来的数据填充

  2、更新数据时,同样只需要传入instance参数,校验通过后,只需调用save方法即可将原来的数据更新。

  3、其余方法与forms基本一致,只是在创建forms类不同

 

以上是关于forms表单与modelfrom使用的主要内容,如果未能解决你的问题,请参考以下文章

Form标签表单回显与提交

javascript对象

将按钮与带有标签的输入表单对齐

将 Crispy 表单与 ModelForm 一起使用

Oracle Forms Builder:无法执行查询

17.FastAPI 表单数据