forms表单与modelfrom使用

nercon 2020-03-03

详细参考链接:点击

数据结构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类不同

相关推荐

bailangsyc / 0评论 2019-12-27