接着搞起烂摊子。
前面我们简单的实现了全篇只读限制,但是存在安全隐患。在解决此隐患之前,我们需要先之道如何实现自定义后台表单的验证。
1. 原生admin中自定义表单验证
说起表单验证,在前面提过Form
和MoldeForm
的相关使用,这里我们要通过另一个方法进行处理。
我们通过使用clean()
方法实现对全部字段进行验证操作,clean_name()
单独对每个字段进行验证处理,其中name
对应字段名称(必须保持一致)。
这些实际的使用方式就不具体介绍了,简单的介绍一下实现原理:
实际的代码中,我们只需要在定义的From
文件中添加即可:
1 from django import forms 2 3 class LoginForm(forms.Form): 4 5 def clean_user(self): 6 c = UserProfile.objects.filter(name=self.cleaned_data[‘user’]).count() 7 if not c: 8 return self.cleaned_data[‘user’] 9 else: 10 raise ValueError(“用户名已经存在”, code=”asdasd”) 11 12 def clean_pwd(self): 13 pass 14 15 def clean(self): # 对整体验证 16 c = UserProfile.objects.filter(name=self.cleaned_data[“user”], pwd=self.cleaned_data[“pwd”]) 17 if c: 18 return self.cleaned_data 19 else: 20 raise ValueError(“用户名密码错误”)
这里只是提供简单的示例。
2. 构造自定义功能
2.1 所有字段添加自定义clean()验证
前面我们动态创建了MoelForm
的每个具体类,我们要为每个类中添加clean()
验证。既然,我们动态创建了类,那么对应的类的方法也是很简单的。
在上面的图中,我们可以看出clean()
方法调用的原理,下面结合之前的只读限制来使用它,上一篇文章中我们实现了只读功能,但是并没有安全的验证机制,为了安全做如下操作:
这里先不做多对多的关系处理
2.2 不处理多对多关系
在king_admin
应用目录下的forms.py
中添加如下代码:
1 def __new__(cls, *args, **kwargs): 2 # 遍历数据库的所有字段和字段对应的对象 3 for field_name, field_obj in cls.base_fields.items(): 4 # 为字段对象的组件添加class属性 5 field_obj.widget.attrs[‘class’] = ‘form-control’ 6 7 #添加只读限制 8 if not hasattr(admin_class, ‘is_add_form’): #排除添加页面 9 if field_name in admin_class.readonly_fields: 10 field_obj.widget.attrs[‘disabled’] = ‘disabled’ 11 # 创建当前类的实例—>即创建子类 12 return ModelForm.__new__(cls) 13 14 #为每个ModelForm具体的类创建clean()方法 15 def clean_init(self): 16 “”” 17 :param self: 表单对象 18 :return: 19 “”” 20 error_list = [] #存储错误 21 for field in admin_class.readonly_fields: 22 #获取数据库的数据 23 field_db = getattr(self.instance, field) 24 #获取前端数据 25 field_input = self.cleaned_data.get(field) 26 #判断 27 if field_db != field_input: 28 #触发错误,固定格式 29 error_list.append( 30 ValidationError( 31 ‘Field %(field)s is readonly,data should be %(value)s’, 32 code=’invalid’, 33 params={‘field’: field,’value’: field_db} 34 ) 35 ) 36 #集中错误 37 if error_list: 38 raise ValidationError(error_list) 39 40 <——————-为对象添加属性——————————– 41 #为该类添加__new__静态方法,当调用该类时,会先执行__new__方法,创建对象 42 # 这里会覆盖父类的__new__ 43 setattr(_model_form_class, ‘__new__’, __new__) 44 45 #添加clean()方法到生成的表单类 46 setattr(_model_form_class, ‘clean’, clean_init) 47 48 return _model_form_class 49
基本的逻辑实现完毕,修改指定的只读字段
1 ... 2 #自定义类,显示特定字段 3 class CustomerAdmin(ModelAdmin): 4 list_display = ['id', 'qq','name','source','consultant','consult_course','date','status'] 5 list_filters = ['source','consultant','consult_course','status'] 6 search_fields = ['qq', 'name', 'consultant__name', ] 7 ordering = 'date' 8 # filter_horizontal = ['tags'] 9 readonly_fields = ['qq', 'name'] #添加该字段 10 readonly_table = False 11 list_per_page = 2 12 ...
效果如下: