一、创建一个ModelForm组件
1、导入相应模块
from django.forms import ModelForm
from django.forms import fields
2、创建一个类来继承ModelForm(类中继承类,规定)
class UserModelForm(ModelForm):
UserInfo表中的字段名=fields.ChoiceField(choices=[(x1,y1),(x2,y2),(x3,y3)],error_messages='错误信息') #默认情况下在前端会把表字段渲染成一个个input标签,可以通过fields来定制在前端渲染成其他标签,比如select标签,这时x1就会作为value值,y1就会作为文本在前端显示,但是有个缺点是在前端添加的新数据不会自动刷新,解决办法如下(手动挡和自动挡) class Meta: model = models.UserInfo #UserInfo 是在model中相关的表名 fields = "__all__" #all表示继承表中所有字段,也可以用列表的方式继承某个字段(fields=['表字段1','表字段2','表字段3']),想显示几个字段就写几个字段。
UserInfo表中的字段名=fields.ChoiceField(error_messages='错误信息') #手动挡,手动刷新
def __init__(self,*args,**kwargs):
super(UserModelForm,self).__init__(*args,**kwargs)
self.fields['UserInfo表中的字段名'].choices=[(x1,y1),(x2,y2),(x3,y3)] #得到的是个列表嵌套元组
from django.forms.models import ModelChoiceField #自动挡,自动刷新
UserInfo表中的字段名=ModelChoiceField(queryset=models.Userinfo.all()) #得到的是个对象,但是依赖性差,必须写___str__
3、函数中调用该类,用于在前端显示models中的字段信息
注释:get方式是请求数据,post方式是发送数据,增加数据库记录 def user_add(request): if request.method == 'GET': model_form = UserModelForm() #类实例化产生一个对象,该对象就有了该model中所有字段 return render(request,'rbac/user_add.html',{ 'model_form':model_form}) #将类对象传输到前端页面进行渲染,由于传输的是all,所以model中有几个值就渲染几个。可通过novalidate来禁止浏览器自身渲染 else: model_form = UserModelForm(request.POST) #将客户端发送过来的数据进行类实例化产生一个对象,该对象就有了表字段中所对应的所有客户端的数据 if model_form.is_valid(): #将该对象下的客户数据进行验证,判断如果符合条件则pass model_form.save() #将客户端符合条件的数据保存起来,直接通过save()方式就可以在数据库中创建数据以及外键对应关系 return redirect('/rbac/users.html') return render(request, 'rbac/user_add.html', { 'model_form': model_form})
4、函数中调用该类,用于在前端显示models中的某一条记录的信息
注释:更新数据库记录,先返回数据库中记录信息给客户端,然后更新数据库记录 def user_edit(request,pk): obj = models.UserInfo.objects.filter(pk=pk).first() #在数据库中查找,得到一条记录对象 if not obj: return redirect('/rbac/users.html') if request.method == 'GET': model_form = UserModelForm(instance=obj) #将在数据库中查找到的数据进行实例化产生一个对象,该对象就分装了该数据的所有相关信息 return render(request,'rbac/user_edit.html',{ 'model_form':model_form}) else: model_form = UserModelForm(request.POST,instance=obj) #必须告诉UserModelForm类是对那条记录进行更新,如果不写就是添加 if model_form.is_valid(): model_form.save() return redirect('/rbac/users.html') return render(request, 'rbac/user_edit.html', { 'model_form': model_form})
5、前端通过as_p的方式进行快速部署
{ { model_form.as_p }}
6、前端可以通过''.''方式选择部署
{ { model_form.label }} #主要表示的是数据的表头信息,即model类中的表字段信息{ { model_form }} #主要表示的是需要添加的数据格式,即input框select框等。{ { model_form.errors}} #主要表示的是数据的错误信息,可以通过errors.0的方式取第一条错误信息
7、前端补充知识
{ { model_form.field}} #主要是得到的是表中的哪个外键字段以及外键字段对应的数据,得到的是个类似于的内存地址,只有是外键的字段才会显示出来{ { model_form.field.queryset}} #主得到的是表中所有字段对象
{ { model_form.auto_id}} #主得到的是表每个字段的id
{ { model_form._meta.app_label}} #主得到的是使用字段的app名称 { { model_form._meta.model_name}} #主得到的是使用字段的表名
{ { model_form.field.queryset.model}} #主得到的是表的类名 总结:具体使用方法可以参考fields源码
二、总结
ModelForm class Meta: model=, # 对应Model的表名 fields=None, # 对应的表字段名,多个时用列表 exclude=None, # 对应的表字段名,只不过是排除字段多个时用列表 labels=None, # 改变原有的用户提示信息 {‘字段名’:‘提示信息’} help_texts=None, # 帮助提示信息 {‘字段名’:‘帮助提示信息’}
widgets=None, # 自定义插件属性需要先导入 from django.forms import widgets 然后 widgets = { "username":widgets.Textarea(attrs={'class':'c1'}) } error_messages=None, # 自定义错误信息字典的形式{'表字段': {'required':'错误提示'},'表字段': {'required':'错误提示'},} (整体错误信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定义字段类型(type) (也可以自定义字段) {‘字段名’:fields.类型名} ,用之前徐先导入from django.forms import fields localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 则显示: 2016-12-27 12:10:57 b. 验证执行过程 is_valid -> full_clean -> 钩子 -> 整体错误 c. 字典字段验证 def clean_字段名(self): #制作钩子,在在ModelForm自带验证客户端数据条件的前写入自己的验证条件,如果没通过就直接走自己的验证机制 # 可以抛出异常 # from django.core.exceptions import ValidationError return "新值" d. 用于验证 model_form_obj = XXOOModelForm() model_form_obj.is_valid() #用于验证客户端传输过来的数据是否符合条件 model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用于创建 model_form_obj = XXOOModelForm(request.POST) #### 页面显示,并提交 ##### # 默认保存多对多 obj = form.save(commit=True) # 不做任何操作,内部定义 save_m2m(用于保存多对多) obj = form.save(commit=False) obj.save() # 保存单表信息 obj.save_m2m() # 保存关联多对多信息 f. 用于更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 单纯初始化 model_form_obj = XXOOModelForm(initial={...})
三、个人总结
1、ModelForm是结合和form和model两种方法的特性,换句话说就是这两种方法的结合体。所以ModelForm既可以用form中的方法也可以使用model中的方法。
2、代码
from django.forms import ModelFormfrom django.forms import widgets as widfrom django.forms import fields as fldclass UserModelForm(ModelForm): # use = fld.CharField() #自定制字段 class Meta: model = models.UserInfo fields = "__all__" # fields = ['username','nickname',] #显示表中的某个字段 # exclude = ['username',] #显示出该字段外的表中所有字段 # error_messages = { # "username": {'required':'用户名不能为空'} #为表中字段自定制错误信息 # } # widgets = { # "username":wid.Textarea(attrs={'class':'c1'}) #为 表中字段自定义标签类型并自定义样式名称 # } # labels = { # 'username':'用户名' #自定义提示信息 # } # help_texts = { # 'username': '别瞎写,瞎写打你哦' #自定义用户提示信息 # } # # field_classes = { # 'username': fld.EmailField #自定义标签类型 # } # def clean_email(self): #自定义某个字段钩子 # pass # # def clean_nickname(self): # pass # # def clean(self): #自定义所有钩子 # pass def user_add(request): # 现在的你# 创建Form类: if request.method == 'GET': model_form = UserModelForm() return render(request,'rbac/user_add.html',{'model_form':model_form}) else: model_form = UserModelForm(request.POST) if model_form.is_valid(): model_form.save() return redirect('/rbac/users.html') return render(request, 'rbac/user_add.html', {'model_form': model_form})def user_edit(request,pk): obj = models.UserInfo.objects.filter(pk=pk).first() if not obj: return redirect('/rbac/users.html') if request.method == 'GET': model_form = UserModelForm(instance=obj) return render(request,'rbac/user_edit.html',{'model_form':model_form}) else: model_form = UserModelForm(request.POST,instance=obj) if model_form.is_valid(): model_form.save() return redirect('/rbac/users.html') return render(request, 'rbac/user_edit.html', {'model_form': model_form})
注释:novalidate
可以禁止掉浏览器自带的form验证(HTML5给form元素新增了一个novalidate属性,指定为true或者就直接仅仅声明这个属性的时候,不会验证字段)