目录
ModelForm.. 1
Model field与Form field:... 1
ModelForm save()方法:... 4
ModelForm Meta:... 5
ModelForm自定义验证:... 5
ModelForm initial and instance:... 6
ModelForm
结合了form和model,将model的field类型映射成form的field类型,复用了model的验证,还实现了存储数据库的简单方法,写更简洁的代码;
django提供一个辅助类(class Meta),使之可从Model创建Form;
生成的Form类中将具有和指定的模型字段对应的表单字段,顺序为fields属性中指定的顺序;
Model field与Form field:
每个模型字段有一个对应的默认表单字段,如模型中的ManyToManyField对应表单中的ModelMultipleChoiceField,ForeignKey<-->ModelChoiceField;
例:
mysite/books/models.py
TITLE_CHOICE = (
('MR', 'Mr.'),
('MRS', 'Mrs'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choice=TITLE_CHOICE)
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
mysite/books/forms.py
from django import forms
from django.forms import ModelForm
from .models import Author, Book
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date'] #使用model的全部字段,用field = '__all__',另exclude = ('birth_date')排除的字段列表,建议显式的设置,否则有安全问题
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['name', 'authors']
# from .models import TITLE_CHOICE
# class AuthorForm(forms.Form):
# name = forms.CharField(max_length=100)
# title = forms.CharField(max_length=3, widget=forms.Select(choices=TITLE_CHOICE))
# birth_date = forms.DateField(required=False)
#
# class BookFrom(forms.Form):
# name = forms.CharField(max_length=100)
# authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
注:
模型字段blank=True,表单字段require=False;
模型字段verbose_name(首字段大写the first character capitalized),表单字段label;
模型字段help_text,表单字段help_text;
模型字段choices,表单字段widget=forms.Select(choices=TITLE_CHOICE),choices从模型中来,选项通常会包含空选项,且默认会选择,如果字段是必选的,它会强制用户选择一个选项,如果模型字段的default且有一个显示default值,将不会包含空选项(初始值即blank=False);
ModelForm save()方法:
这个方法根据表单绑定的数据创建并保存数据库对象;
save()接受关键字参数commit,book=save(commit=False)时:
1将返回一个还没有保存到数据库的对象,这种情况下,要调用模型实例的form.save(),
2在多对多关系时指定commit=False,django不会立即为多对多有关系保存表单数据(只有实例在数据库中存在时才可保存实例的多对多关系),要手动调用save_m2m()来保存多对多的表单数据
save_m2m()仅在save(commit=False)时才用到;
>>> from publish.models import Author,Book
>>> from publish.forms import AuthorForm,BookForm
>>> form = AuthorForm({'name':'jowin','title':'MR'})
>>> form.is_valid()
True
>>> form.is_bound
True
>>> form.save() #author=form.save(),后续用返回的对象
>>> form = AuthorForm({'name':'mage','title':'MR'})
>>> form.is_valid()
True
>>> form.save() #author=form.save()
>>> authors = Author.objects.all()
>>> authors_id = [author.id for author in authors]
>>> form = BookForm({'name':'django book','authors':authors_id})
>>> form.is_valid()
True
>>> form.save() #book=form.save()
>>> form = BookForm({'name':'py book','authors':authors_id})
>>> form.is_valid()
True
>>> form.save()
>>> form = BookForm({'name':'js book','authors':authors_id})
>>> form
>>> book = form.save(commit=False)
>>> book
>>> book.name = 'react book'
>>> book.save()
>>> form.save_m2m()
>>> book.name
'react book'
ModelForm Meta:
mysite/publish/forms.py
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date'] #fields = '__all__';exclude = ('birth_date')
labels = {'name': 'Writer'}
widgets = {'name': Textarea(attrs={'cols': 80, 'rows': 20})} #forms.Textarea()
help_texts = {'name': 'Some useful help text'}
error_messages = {'name': {'max_length': "This writer's name is too long."}}
ModelForm自定义验证:
mysite/publish/forms.py
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date'] #fields = '__all__';exclude = ('birth_date')
labels = {'name': 'Writer'}
widgets = {'name': Textarea(attrs={'cols': 80, 'rows': 20})}
help_texts = {'name': 'Some useful help text'}
error_messages = {'name': {'max_length': "This writer's name is too long."}}
def clean(self):
cleaned_data = super(AuthorForm, self).clean()
name = cleaned_data.get('name')
title = cleaned_data.get('title')
if len(name) < 40 and title == 'MR':
raise ValidationError('Field: {} and {} is error'.format(name, title))
def clean_name(self): #clean_
name = self.cleaned_data['name']
if len(name) < 30:
raise ValidationError('length must more than 30')
return name
ModelForm initial and instance:
提供初始值;
mysite/publish/views.py #view中使用modelform
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .forms import AuthorForm
from .models import Author
def index(request):
if request.method == 'POST':
form = AuthorForm(request.POST)
if form.is_valid():
publish = form.save()
return HttpResponse('ok')
else:
form = AuthorForm()
return render(request, 'publish/publish.html', {'form': form})
def update(request, publish_id):
author = get_object_or_404(Author, id=publish_id)
if request.method == 'POST':
form = AuthorForm(request.POST, instance=author) #更新时要加instance,否则认为是新创建,也可form=AuthorForm(request.POST,initial={'name':'test'})
if form.is_valid():
author = form.save()
return HttpResponse('add succeed')
form = AuthorForm(instance=author) #initial={'name':'test'}
return render(request, 'publish/publish.html', {'form': form})
mysite/publish/models.py
from django.db import models
TITLE_CHOICE = (
('MR', 'Mr.'),
('MRS', 'Mrs'),
('MS', 'Ms.'),
)
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICE)
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)