一、定义ModelForm类
# 创建部门表单校验
class DepartmentForm(forms.ModelForm): class Meta: model = models.Department #关联到Models中的表名Department fields = '__all__' #获取Department表中的所有对象,也可以写成列表['depName','depDes'],指定要获取的对象,而且是有顺序的 labels = { 'depName': '部门名称', 'depDes': '职责描述', } widgets = { #设置插件,type类型和类名等属性 'depName': forms.TextInput(attrs={'class': 'form-control','placeholder':'请输入部门名称'}), 'depDes': forms.TextInput(attrs={'class': 'form-control','placeholder':'请输入部门职责描述'}), }
class Meta:下常用参数:
model = models.Department # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段,也可以写成列表['title','price'],指定要获取的对象
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件,form组件里是widget,ModelForm组件里是widgets
error_messages = None # 自定义错误信息
其中label属性可以不在ModelForm这里面写,也可以在models.py中的Depart表中各个对象定义verbose_name属性值,用于非ForeignKey对象,
推荐这种写法,在Admin系统中也可以显示这里定义的verbose_name值
class Depart(models.Model): depName = models.TextField(max_length=32, verbose_name='部门名称') depDes = models.TextField(max_length=64, black=True, null=True, verbose_name='职责描述')
二、批量添加样式
可通过重写ModelForm类的init方法来实现。
# 创建部门表单校验
class DepartmentForm(forms.ModelForm): depName = forms.TextField(validators=[],) #如果depName字段存在,就代表重写这个字段 count = forms.TextField(validators=[],) #如果count字段不存在,就代表新增这个字段,models文件中不存在这个字段 class Meta: model = models.Department #model和fields都是固定写法,不能写 fields = '__all__' labels = { 'depName': '部门名称', 'depDes': '职责描述', } widgets = { 'depName': forms.TextInput(attrs={'placeholder':'请输入部门名称'}), 'depDes': forms.TextInput(attrs={'placeholder':'请输入部门职责描述'}), 'purchase_date': forms.widgets.DateInput(attrs={'type': 'date'}), 'expiration_date': forms.widgets.DateInput(attrs={'type': 'date'}), } error_messages = { #这里的error_messages只能写默认存在的校验字段 'depName':{ 'required':'不能为空' } } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in self.fields.values(): field.widget.attrs.update({'class': 'form-control'}) class DepartAdd(View): def get(self, request): form_obj = DepartmentForm() return render(request, 'departadd.html', {'form_obj': form_obj}) def post(self, request): form_obj = DepartmentForm(request.POST) print(form_obj) if form_obj.is_valid(): # models.Department.objects.create(**form_obj.cleaned_data) form_obj.save() #直接save()方法就可以保存 return redirect(reverse('departList'))
三、部门添加、修改例子(FVB版)
部门添加
def depart_add(request): form_obj = departForm.DepartForm() if request.method == 'POST': form_obj = departForm.DepartForm(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(reverse('depart_list')) return render(request, 'depart/depart_add.html', {'form_obj': form_obj})
部门修改
def depart_edit(request, pk): form_edit = models.Depart.objects.filter(pk=pk).first() form_obj = departForm.DepartForm(instance=form_edit) if request.method == 'POST': form_obj = departForm.DepartForm(request.POST, instance=form_edit) #这里要将当前对象作为一个实例传给ModelForm # 如果没有修改,则不需要校验 depart_name_new = request.POST.get('depart_name', None) if form_edit.depart_name == depart_name_new: # 部门描述不需要校验,直接更新保存 form_edit.depart_desc = request.POST.get('depart_desc', None) form_edit.save() return redirect(reverse('depart_list')) # 如果修改了值,就调用DepartForm校验,注意用instance表示将当前对象传给Modelform校验,模板中字段仍然可以自动生成 elif form_obj.is_valid(): form_obj.save() return redirect(reverse('depart_list')) return render(request, 'depart/depart_edit.html', {'form_edit': form_edit, 'form_obj': form_obj})
前端页面
展示页面depart_list.html
<table class="form-horizontal table table-bordered" style="margin-top: 10px"> <thead> <tr> <th>ID</th> <th>用户名称</th> <th>密码</th> <th>所属部门</th> <th>操作</th> </tr> </thead> <tbody> {% for user in user_all %} <tr> <td>{{ forloop.counter }}</td> <td>{{ user.username }}</td> <td>{{ user.pwd }}</td> {# <td>{{ user.depart.depart_name}}</td>#} #这里可以通过depart外键.depart_name来获取部门名称进行前端页面显示 <td>{{ user.depart }}</td> #也可以通过在models.py中给Depart类写__str__方法,这里就不需要用点方法了 <td> <a href="{% url 'user_edit' user.pk %}"><i class="fa fa-edit fa-2x"></i></a> <a class="del" del_obj="user" del_id="{{ user.pk }}"><i class="fa fa-trash-o fa-2x" style="cursor: pointer;"></i></a> </td> </tr> {% endfor %} </tbody> </table>
修改页面depart_edit.html
<form action="" method="post" class="form-horizontal"> {% csrf_token %} <div class="form-group {% if form_obj.depName.errors %}has-error{% endif %}"> <label for="{{ form_obj.depName.id_for_label }}" class="col-lg-2 control-label">{{ form_obj.depName.label }}</label> <div class="col-lg-6"> {{ form_obj.depName}} </div> <span class="help-block">{{ form_obj.errors.0 }}</span> </div> bootstrape样式中使用has-error和help-block类渲染错误提示效果
models.py
from django.db import models # Create your models here. class Depart(models.Model): depart_name = models.CharField(max_length=32, verbose_name='部门名称') depart_desc = models.CharField(max_length=64, verbose_name='部门描述') #通过写__str__方法,前端直接调用depart对象时就可以直接获取到depart_name的值了 def __str__(self): return self.depart_name class User(models.Model): username = models.CharField(max_length=32, verbose_name='用户名') pwd = models.CharField(max_length=32, verbose_name='密码') depart = models.ForeignKey(to='Depart', verbose_name='所属部门')
四、代码合并
1、depart_all.html模板代码合并
未合并写法,写了多个form-group,重复
<form action="" method="post" class="form-horizontal" novalidate> {% csrf_token %} <div class="form-group {% if form_obj.depart_name.errors %}has-error{% endif %}"> <label for="{{ form_obj.depart_name.id_for_label }}" class="col-lg-2 control-label"> {{ form_obj.depart_name.label }} </label> <div class="col-lg-6"> {{ form_obj.depart_name }} <span class="help-block">{{ form_obj.depart_name.errors.0 }}</span> </div> </div> <div class="form-group {% if form_obj.depart_desc.errors %}has-error{% endif %}"> <label for="{{ form_obj.depart_desc.id_for_label}}" class="col-lg-2 control-label "> {{ form_obj.depart_desc.label }} </label> <div class="col-lg-6"> {{ form_obj.depart_desc }} <span class="help-block">{{ form_obj.depart_desc.errors.0 }}</span> </div> </div> <div class="form-group"> <div class="col-lg-10 col-lg-offset-2"> <button class="btn btn-primary">提交</button> </div> </div> </form>
合并写法
<form action="" method="post" class="form-horizontal" novalidate> {% csrf_token %} {#需要渲染多个form-group, 可以使用for循环避免重新编写,将form_obj.depart_name和form_obj.depart_desc改成field即可#} {% for field in form_obj %} <div class="form-group {% if field.errors %}has-error{% endif %}"> <label for="{{ field.id_for_label }}" class="col-lg-2 control-label"> {{ field.label }} </label> <div class="col-lg-6"> {{ field }} <span class="help-block">{{ field.errors.0 }}</span> </div> </div> {% endfor %} <div class="form-group"> <div class="col-lg-10 col-lg-offset-2"> <button class="btn btn-primary">提交</button> </div> </div> </form>
2、views.py视图代码合并
未合并写法
urls.py url(r'^user/add/$', user.user_add, name='user_add'), url(r'^user/edit/(\d+)/$', user.user_edit, name='user_edit'), views.py #用户添加函数 def user_add(request): form_obj = userForm.UserForm() if request.method == 'POST': form_obj = userForm.UserForm(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(reverse('user_list')) return render(request, 'user/user_add.html', {'form_obj': form_obj}) #用户编辑函数 def user_edit(request, pk): obj = models.User.objects.filter(pk=pk).first() form_obj = userForm.UserForm(instance=obj) if request.method == 'POST': form_obj = userForm.UserForm(request.POST, instance=obj) # 如果未修改原值,则不校验 if request.POST.get('username', None) == obj.username: obj.pwd = request.POST.get('pwd', None) obj.gender = request.POST.get('gender', None) # depart不能直接保存为request.POST.get('depart',None),因为depart是一个外键,需要保存Depart的一个实例 obj.depart = models.Depart.objects.filter(pk=request.POST.get('depart', None)).first() obj.save() # 这里先创建用户的时候校验密码不能为空,但是修改用户时没有校验密码是否为空 return redirect(reverse('user_list')) # 修改了原值,则进行校验 elif form_obj.is_valid(): form_obj.save() return redirect(reverse('user_list')) return render(request, 'user/user_edit.html', {'form_obj': form_obj})
将用户添加函数和用户编辑函数合并编写
将urls中函数方法统一写成user_change,在views中只需要写一个user_change函数包含用户添加和编辑功能。 urls.py url(r'^user/add/$', user.user_change, name='user_add'), url(r'^user/edit/(\d+)/$', user.user_change, name='user_edit'), views.py 由于用户添加和编辑函数逻辑相似,可以合并编写 区别就是编辑函数需要传入pk值,而添加函数不需要传入pk值,所以设置pk=None默认为空 其他代码基本相同 def user_change(request, pk=None): #如果是添加方法,则obj为空 obj = models.User.objects.filter(pk=pk).first() form_obj = userForm.UserForm(instance=obj) if request.method == 'POST': form_obj = userForm.UserForm(request.POST, instance=obj) if obj: # 如果未修改username原值,则不校验 if request.POST.get('username', None) == obj.username: obj.pwd = Md5(request.POST.get('pwd', None)).md5 obj.gender = request.POST.get('gender', None) # depart不能直接保存为request.POST.get('depart',None),因为depart是一个外键,需要保存Depart的一个实例 obj.depart = models.Depart.objects.filter(pk=request.POST.get('depart', None)).first() obj.save() # 这里先创建用户的时候校验密码不能为空,但是修改用户时没有校验密码是否为空 return redirect(reverse('user_list')) # 修改了原值,则进行校验 elif form_obj.is_valid(): form_obj.save() return redirect(reverse('user_list')) return render(request, 'user/user_edit.html', {'form_obj': form_obj})