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 = '作者'
在页面上对数据进行操作时,如果不用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>
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框
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})
<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>
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添加数据 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})
<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>
1、modelform接收一个参数instance,为model对象,它自动将这个model对象的每个字段值填充到form表单,前端页面的输入框自动将原来的数据填充
2、更新数据时,同样只需要传入instance参数,校验通过后,只需调用save方法即可将原来的数据更新。
3、其余方法与forms基本一致,只是在创建forms类不同
modelform字段对象方法:
class ModelForms(forms.ModelForm): class Meta: model = self.model fields = '__all__' widgets = {'publishDate': forms.widgets.TextInput(attrs={'type': 'date', }),} forms_obj = ModelForms() for forms_field_obj in forms_obj: print('-------', forms_field_obj, type(forms_field_obj)) # django.forms.boundfield.BoundField print('+++++++', forms_field_obj.field, type(forms_field_obj.field)) # <class 'django.forms.models.ModelMultipleChoiceField'> # modelform字段对象 print('*******', forms_field_obj.name, type(forms_field_obj.name)) # authors <class 'str'> 字段名字(字符串) print(forms_field_obj.field.queryset, type(forms_field_obj.field.queryset)) # 返回这个关系字段下所有的对象 print(forms_field_obj.field.queryset.model, type(forms_field_obj.field.queryset.model)) # 返回这个关系字段的关联模型表 app_label = forms_field_obj.field.queryset.model._meta.app_label # 获取关联字段的关系模型表所在的app model_name = forms_field_obj.field.queryset.model._meta.model_name # 获取关联字段的关系模型表的表名