Django中三种方式写form表单
除了在html中自己手写form表单外,django还可以通过 继承django.forms.Form 或django.forms.ModelForm两个类来自动生成form表单,下面依次利用三种方式来实现form表单,实现向数据库中添加书籍的页面,效果如下:
首先在models类中定义了Book,Author和Publish类,并定义了关联关系,publish,author和book分别为一对多和多对多关系,代码如下:
class Book(models.Model): title = models.CharField(max_length=64) price = models.DecimalField(max_digits=5,decimal_places=2,default=0) author = models.ManyToManyField(to='Author') publish = models.ForeignKey(to='Publish') def __str__(self): return self.title class Author(models.Model): name = models.CharField(max_length=128) age = models.IntegerField() def __str__(self): return self.name class Publish(models.Model): name = models.CharField(max_length=255) address = models.CharField(max_length=255) def __str__(self): return self.name
1 原生form表单
在html页面中手写表单,很简单,直接上代码,对应的Html和视图函数如下:
addbook.html
<form action="" method="post"> {% csrf_token %} <p > <label>书籍标题:</label> <input type="text" name="title" class="form-control"/> </p> <p> <label>价格:</label> <input type="number" name="price" class="form-control"/> </p> <p> <label>出版社:</label> <select name="publish" class="form-control"> {% for publish in publishs %} <option value="{{ publish.pk }}">{{ publish.name }}</option> {% endfor %} </select> </p> <p> <label>作者:</label> <select multiple="multiple" name="author" class="form-control"> {% for author in authors %} <option value="{{ author.pk }}">{{ author.name }}</option> {% endfor %} </select> </p> <input type="submit" value="保存"/> </form>
views.py
def addbook(request): authors = models.Author.objects.all() publishs = models.Publish.objects.all() if request.method=='POST': title = request.POST.get('title') price = request.POST.get('price') author = request.POST.getlist('author') publish = request.POST.get('publish') # print author, publish book_obj = models.Book.objects.create(title=title,price=price,publish_id=publish) book_obj.author.add(*author) #此时添加的为author的id值 [u'1', u'3] # for i in author: # book_obj.author.add(int(i)) # book_obj.save() return redirect('/listbook/') return render(request,'addbook.html',locals())
2 继承django.forms.Form类
model 字段和form字段的对应关系
首先定义一个BookForm类,继承forms.Form,根据models中定义的Book类,逐个定义相应的字段,字段中可以定义相应的参数,如required=True,表示默认为True,字段不能为空;label定义标签;initial设置初始值;以及error_messages和widget等,参数详细使用见https://docs.djangoproject.com/zh-hans/2.0/ref/forms/fields/。
BookForm类如下:
class BookForm(forms.Form): title=forms.CharField( label='书籍标题', max_length=32, widget=forms.widgets.TextInput(attrs={'class':'form-control'}) ) price = forms.DecimalField( label='价格', widget=forms.widgets.TextInput(attrs={'type':'number','class':'form-control'}) ) # 设置type来改变类型,显示数字输入框 publish = forms.ModelChoiceField( label='出版社', queryset=models.Publish.objects.all(), widget=forms.widgets.Select(attrs={'class': 'form-control'}) ) # gender=forms.ChoiceField(choices=((1,"男"),(2,"女"),(3,"其他"))) # publish=forms.ChoiceField(choices=Publish.objects.all().values_list("pk","title")) #ModelChoiceField继承了ChoiceField author = forms.ModelMultipleChoiceField( label='作者', queryset=models.Author.objects.all(), widget=forms.widgets.SelectMultiple(attrs={'class': 'form-control'}) )
定义好BookForm类后只需在视图函数中进行实例化,并将实例传给前端html,就能自动生成表单,视图函数和html代码如下。BookForm类除了能自动生成前端表单外,还能对数据进行校验,若校验通过,is_valid()方法返回True,并将校验后的数据以字典形式封装到cleaned_data中
views.py
def addbook(request): if request.method=='POST': form = BookForm(request.POST) if form.is_valid(): author = form.cleaned_data.pop('author') # print form.cleaned_data, author book_obj = models.Book.objects.create(**form.cleaned_data) for i in author: book_obj.author.add(i) #此时添加的为author queryset对象 book_obj.save() return redirect('/listbook/') form = BookForm() return render(request,'addbook.html',locals())
addbook.html
<form action="" method="post"> {% csrf_token %} {% for field in form %} <div > {{ field.label }} {{ field }} </div> {% endfor %} <input type="submit" value="保存"/> </form>
3 继承django.forms.ModelForm类
定义一个BookModelForm类,继承forms.ModelForm,相比forms.Form其更加简单,不用逐个定义字段,只需将Book类和需要显示的字段传入,也可以自定义label,widget等参数,详细使用见 https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/
BookModelForm类如下:
class Meta: model = models.Book fields = '__all__' # 类似于fields = ['title','price','publish','author'],可以自定义需要显示的字段,__all__为所有字段 labels = { 'title': '书籍名称', 'price': '价格', 'author':'作者', 'publish': '出版社' } widgets = { 'title':forms.widgets.TextInput(attrs={'class':'form-control'}), 'price':forms.widgets.TextInput(attrs={'class':'form-control','type':'number'}), 'author': forms.widgets.SelectMultiple(attrs={'class': 'form-control'}), 'publish': forms.widgets.Select(attrs={'class':'form-control'}) } #必须按定义的字段顺序排列
和forms.Form一样,在视图函数中向前端传入BookModelForm实例对象,就能自动生成form表单,但其对表单数据处理更加简单,可以直接调用save方法,而且若未对表单数据校验时,save方法会对数据进行校验,另外可以通过BookModelForm(request.POST,instance=a)形式来传入单个实例,储存一条数据记录,如下:
>>> a = Article.objects.get(pk=1) >>> f = ArticleForm(request.POST, instance=a) >>> f.save()
具体的视图函数和前端代码如下:
views.py
def addbook(request): form = BookModelForm() if request.method=='POST': form = BookModelForm(request.POST) # 参数中还可以传单个实例,来储存一条数据 form.save() # 若未进行数据校验时,save()方法会对数据进行校验 return redirect('/listbook/') return render(request,'addbook.html',locals())
addbook.html
<form action="" method="post"> {% csrf_token %} {% for field in form %} <div > {{ field.label }} {{ field }} </div> {% endfor %} <input type="submit" value="保存"/> </form>
相关参考博客:http://www.cnblogs.com/yuanchenqi/articles/8034442.html
http://www.cnblogs.com/yuanchenqi/articles/7614921.html