除了在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