modelform组件以及ChoiceField属性
一. Forms组件补充
1.__init__()
如果继承forms.Form的类中的每一个字段,或者大部分字段都做了相同的约束,可以将该约束放到__init__中编写
实例:每一个字段都需要添加form-control类名
1 class BookForm(forms.Form): 2 title = forms.CharField(max_length=32) 3 pub_date = forms.DateField() 4 price = forms.DecimalField(max_digits=8, decimal_places=2) 5 6 def __init__(self,*args,**kwargs): 7 super().__init__(*args,**kwargs) 8 for field in self.fields.values(): 9 field.widget.attrs.update({"class":"form-control"})
2.ChoiceField属性,下拉菜单(元组套元组的形式)
(1)choices作用:在数据库中用元组的第一项作为存储的值,在显示时,将元组的第二项作为显示的内容,便于前端使用下拉框
例:
1 class Book(models.Model): 2 id=models.AutoField(primary_key=True) 3 title=models.CharField(max_length=32) 4 gender=models.IntegerField(choices=((1,"男"),(2,"女")),default=1)
(2)与get_gender_display()方法同时使用,用来获取元组第二项的内容
(3)在forms组件中渲染时,只需将类型改变成ChoiceField()
例:
1 class BookForm(forms.Form): 2 title = forms.CharField(label="书名",max_length=32) 3 pub_date = forms.DateField(label="出版社") 4 price = forms.DecimalField(label="价格",max_digits=8, decimal_places=2) 5 gender=forms.ChoiceField(choices=((1,"男"),(2,"女")))
(4) Choices的问题:小元组的内容是固定的,无法随着数据库的更改二更改,不灵活
3.ModelChoiceField属性
作用:帮助渲染前端页面的下拉框
优势:ModelChoiceField可以接收queryset属性的参数,内容可以随着数据库的更改而更改
例:
1 class BookForm(forms.Form): 2 title = forms.CharField(label="书名",max_length=32) 3 gender=forms.ChoiceField(choices=((1,"男"),(2,"女"))) 4 publish=forms.ModelChoiceField(queryset=Publish.objects.all())
4.ModelMultipleChoiceField属性
作用:帮助前端渲染页面的多选框,内容也能随着数据库的改变而改变
例:
1 class BookForm(forms.Form): 2 gender=forms.ChoiceField(choices=((1,"男"),(2,"女"))) 3 publish=forms.ModelChoiceField(queryset=Publish.objects.all()) 4 author=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
二. modelForm组件
1.作用:
正常情况下的model和form是没有关系的,所有forms组件必须我们自己编写,但是ModelForm可以与model之间形成对应关系,这样就免去了我们自己写model
2.语法:
(1)需要先引入forms组件的model类:from django.forms import ModelForm
(2)编写ModelForm类:
1 class BookModelForm(forms.ModelForm): 2 class Meta: 3 model=Book #与之关联的模型类 4 # fields="__all__" #可以渲染所有字段 5 fields=["title","price"] #可以渲染部分字段 6 7 exclide=[“title”] #可以渲染除某些字段外的所有字段
(3)为公共字段或大多数字段添加内容,批量处理(添加__init__方法)
Input标签的样式属性:
1 def __init__(self,*args,**kwargs): 2 super().__init__(*args,**kwargs) 3 for field in self.fields.values(): 4 field.widget.attrs.update({"class":"form-control"})
将错误转换成中文:
1 def __init__(self,*args,**kwargs): 2 super().__init__(*args,**kwargs) 3 for field in self.fields.values(): 4 field.error_messages={"required":"不能为空"}
(4)为单个字段添加内容(当每个字段的内容不同时)
1 Labels方法: 2 3 class BookModelForm(forms.ModelForm): 4 class Meta: 5 model=Book 6 fields="__all__" 7 labels={"title":"书籍名称","price":"价格"} 8 9 error_messages方法: 10 11 class BookModelForm(forms.ModelForm): 12 class Meta: 13 model=Book 14 fields="__all__" 15 error_messages={"title":{"required":"书籍名称不能为空"}} 16 17 widgets字段: 18 19 先引入:from django.forms import widgets as Fwidgets 20 21 class BookModelForm(forms.ModelForm): 22 class Meta: 23 model=Book 24 fields="__all__" 25 widgets = { 26 'pub_date': Fwidgets.Input(attrs={'type': 'date'}) 27 }
3.forms组件有的接口,modelform也有,如is_valid,clean_data,errors
除了forms组件有的接口外,modelform还有save方法
Save方法会自动将干净的数据添加到表中,含有一对一,一对多,多对多的字段和表也会被处理好
4.编辑页面,默认value值得做法:
(1)取到待编辑的model对象
例:book_obj=Book.objects.fillter(id=1).first()
(2)将model对象传入modelform
例:form=BookModelForm(request.POST,instance=book_obj)
得到的form就是待前端页面渲染的对象
结果:如果对ModelForm传了instance就相当于更新操作,没传instance,就相当于创建操作
三.include
作用:当某一段代码被重复利用的次数很多时,可以将其写到一个文件中,其他地方引用即可,减少代码的冗余性
例:在form.html中
1 <form action="" method="post" novalidate> 2 {% csrf_token %} 3 {% for field in form %} 4 <div class="form-group"> 5 <label for="title">{{ field.label }}</label> 6 {{ field }} 7 <span>{{ field.errors.0 }}</span> 8 </div> 9 {% endfor %} 10 <input type="submit" value="提交" class="btn btn-default pull-right"> 11 </form>
在增加书籍页面中:
1 <!DOCTYPE html> 2 <html lang="zh-CN"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> 8 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" 9 integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> 10 11 </head> 12 <body> 13 <h3>添加书籍</h3> 14 <div class="container"> 15 <div class="row"> 16 <div class="col-md-6 col-md-offset-3"> 17 {% include 'form.html' %} #代表将form.html中的代码放到这里 18 </div> 19 </div> 20 </div> 21 </body> 22 </html>
四.ModelForm的使用模板(做添加和编辑页面)
1.在models.py中:正常写模型表
1 class Book(models.Model): 2 nid=models.AutoField(primary_key=True) 3 title=models.CharField(max_length=32) 4 price=models.DecimalField(max_digits=8,decimal_places=2) # 999999.99 5 pub_date=models.DateTimeField() # "2012-12-12" 6 publish=models.ForeignKey(to="Publish",on_delete=models.CASCADE) 7 authors=models.ManyToManyField(to="Author") 8 9 10 def __str__(self): 11 return self.title
2.在form.py中:构建ModelForm
1 from django.forms import widgets as Fwidgets 2 class BookModelForm(forms.ModelForm): 3 class Meta: 4 model=Book 5 fields="__all__" 6 labels={"title":"书籍名称","price":"价格"} 7 widgets = { 8 'pub_date': Fwidgets.Input(attrs={'type': 'date'}) 9 } 10 def __init__(self,*args,**kwargs): 11 super().__init__(*args,**kwargs) 12 for field in self.fields.values(): 13 field.widget.attrs.update({"class":"form-control"}) 14 field.error_messages={"required":"不能为空"} 15 16 等同于写了以下代码: 17 18 class BookForm(forms.Form): 19 20 21 title=forms.CharField(max_length=32) 22 price=forms.IntegerField() 23 pub_date=forms.DateField(widget=widgets.TextInput(attrs={"type":"date"})) 24 #publish=forms.ChoiceField(choices=[(1,"AAA"),(2,"BBB")]) 25 publish=forms.ModelChoiceField(queryset=Publish.objects.all()) 26 authors=forms.ModelMultipleChoiceField(queryset=Author.objects.all())
3.添加逻辑
1 def add(request): 2 3 if GET请求: 4 5 form=BookModelForm() 6 7 return render(request,{“form”:form}) 8 9 else POST请求: 10 11 form=BookModelForm(request.POST) 12 13 if form.is_valid(): 14 15 form.save() 16 17 return render(“/”) 18 19 else: 20 21 return render(request,{“form”:form})
4.编辑逻辑
1 def edit(request,id): 2 3 edit_obj=Book.objects.get(pk=id) 4 5 if GET请求: 6 7 form=BookModelForm(instance=edit_obj) 8 9 return render(request,{“form”:form}) 10 11 else POST请求: 12 13 form=BookModelForm(request.POST,instance=edit_obj) 14 15 if form.is_valid(): 16 17 form.save() 18 19 return rediecr(“/”) 20 21 else: 22 23 return render(request,{“form”:form})
5.登录和编辑共同的渲染页面
1 <form action="" method="post" novalidate> 2 3 4 {% csrf_token %} 5 {% for field in form %} 6 <div class="form-group"> 7 <label for="title">{{ field.label }}</label> 8 {{ field }} 9 <span>{{ field.errors.0 }}</span> 10 </div> 11 {% endfor %} 12 <input type="submit" value="提交" class="btn btn-default pull-right"> 13 14 15 </form>