仿照Django Admin实现对readonly的字段进行设置

功能点:

  1.页面不可进行更改

  2.如果改变html代码中的值,则需要进行后端的数据库数据校验

  3.可以对某些字段进行自定制校验规则

一.页面展示该字段不可更改

思路:

  1.在king_admin中的自定义admin_class中配置不可更改的列

  2.在forms中循环views传递的admin_class中的readonly_fields,如果有则在__init__方法中加入disabled

3.在前端循环展示

1.在每个admin_class中添加readonly_fields属性

class CustomerAdmin(BaseAdmin):
list_display = ['qq','name','source','consultant','consult_course','date','status']
list_filters = ['source','consultant','consult_course','status','date']
search_fields = ['qq','name','consultant__name']
list_per_page = 5
ordering = 'id'
filter_horizontal = ['tags',]
actions = ['delete_selected_objs','test',]
readonly_fields = ['qq','consultant','tags',] #写上不可被修改的字段

2.在__new__方法中添加readonly字段的disabled属性

    def __new__(cls,*args,**kwargs):
#动态生成样式
for field_name,field_obj in cls.base_fields.items():
#给所有的字段加上form-control样式
field_obj.widget.attrs['class'] = 'form-control'
if field_name in admin_class.readonly_fields:
#如果字段是readonly字段,则加上disabled样式,这样在前端展示的时候,显示为不可更改
field_obj.widget.attrs['disabled'] = 'disabled'
if hasattr(admin_class,'clean_%s'%field_name):
#获取admin_class中的自定义的字段校验方法,加入到自动生成的类中
field_clean_func=getattr(admin_class,'clean_%s'%field_name)
setattr(cls,'field_clean_func',field_clean_func)
return ModelForm.__new__(cls)

3.前端展示

单个字段展示,包含外键

<label class="col-sm-2 control-label" style="font-weight:normal">
{#自动从后端生成的model_form获取field字段进行展示#}
{% if field.field.required %}
<b>{{ field.label }}</b>
{% else %}
{{ field.label }}
{% endif %}
</label>

多对多复选框展示

如果多对多字段在admin_class中的readonly_field中,那么手动给其option加上disabled样式,同时删除js时间,将其的值锁定,不可在改变

{% if field.name in admin_class.filter_horizontal %}
{#实现和Django类似的复选框#}
<div class="col-md-4">
{% get_m2m_tags admin_class field form_obj as m2m_obj_tags%}
<select multiple class="filter-select-box-left" id="id_{{ field.name }}_from">
{% if field.name in admin_class.readonly_fields %}
{% for obj_tag in m2m_obj_tags%}
<option disabled="disabled" value="{{ obj_tag.id }}">{{ obj_tag }}</option>
{% endfor %}
{% else %}
{% for obj_tag in m2m_obj_tags%}
<option ondblclick="move_element(this,'id_{{ field.name }}_to','id_{{ field.name }}_from')" value="{{ obj_tag.id }}">{{ obj_tag }}</option>
{% endfor %}
{% endif %}
</select>
</div>
<div class="col-md-4">
{% get_m2m_selected_tags form_obj field as select_tags%}
<select tag="choose_list" multiple name="{{ field.name }}"class="filter-select-box-right" id="id_{{ field.name }}_to">
{% if field.name in admin_class.readonly_fields %}
{% for obj_tag in select_tags %}
<option disabled="disabled" value="{{ obj_tag.id }}">{{ obj_tag }}</option>
{% endfor %}
{% else %}
{% for obj_tag in select_tags %}
<option ondblclick="move_element(this,'id_{{ field.name }}_from','id_{{ field.name }}_to')" value="{{ obj_tag.id }}">{{ obj_tag }}</option>
{% endfor %}
{% endif %}
</select>
</div>
<span style="color:red">{{ field.errors }}</span>
{% else %}
{{ field }}
<span style="color:red">{{ field.errors }}</span>
{% endif %}

二.后端数据校验

思路:

  1.获取数据库中的值

  2.获取前端表单的值

3.两者进行比较,如果不相等,就抛出异常,同时调用自定义的用户字段验证

 def default_clean(self):
#self指的是前端提交的post表单对象和数据库查询的对象
#所有的表单都适用,readonly字段的后端验证
for field in admin_class.readonly_fields:
#根据admin_class中获取readonly_fields的字段
field_obj_db = getattr(self.instance,field) #获取其在数据库中的值
     #多对多字段的readonly_field后端校验 
if hasattr(field_obj_db,'select_related'):
#如果readonly_field包含多对多的字段
m2m_objs = getattr(field_obj_db,'select_related')().select_related()#获取其在数据库中的对象
m2m_values = [i[0] for i in m2m_objs.values_list('id')]#获取其在多对多的对应的字段的id值
if set(m2m_values) != set([i.id for i in self.cleaned_data.get(field)]):
#如果数据库中的值和前端传的值不相等,直接加入到异常列表中,展示到前端页面
self.add_error('%s是只读字段,不能修改'%field)
continue
#获取前端表单中readonly_field的值
field_obj_front = self.cleaned_data.get(field) #前端readonly的值
if field_obj_db!=field_obj_front:
#如果和数据库中的值不等,则抛出异常
error_list.append(ValidationError('%s字段是只读字段,不允许更改'%field)) self.ValidationError = ValidationError
#调用用户自定义验证
response= admin_class.default_form_validation(self)
  
#如果异常的列表中有值,打印到前端展示
if response:
error_list.append(response) if error_list:
raise ValidationError(error_list)
setattr(_model_form_class,'clean',default_clean) #设置到自动生成的类中

三.在admin_class中进行自定义字段校验

思路:

  1.在admin_class中的自定义单个字段校验以clean_+字段名开始,整体字段的校验写在default_form_validation方法中

2.在from.py中的default_clean方法中集中调用进行验证

整体校验

def default_form_validation(self):
'''整体表单字段的验证'''
content = self.cleaned_data.get('content') #获取前端表单的值
if len(content)<=15:
return self.ValidationError('content字段的值不能少于15个字符')

单个字段校验

    def clean_name(self):
'''单个字段校验'''
if not self.cleaned_data['name']:
self.add_error('姓名不能为空')

在form.py中的生成modelform的时候生成校验规则,如果不符合校验规则,则报错给前端页面

自定义单个字段校验

在__new__中,找到admin_class对应的名称,获取clean_+字段名的方法对象,同时将其绑定到类中

  if hasattr(admin_class,'clean_%s'%field_name):
field_clean_func=getattr(admin_class,'clean_%s'%field_name)
setattr(cls,'field_clean_func',field_clean_func)

自定义整体校验

 self.ValidationError = ValidationError
response= admin_class.default_form_validation(self) #此处传入的self即为views中传入的instance_obj对象和前端的request.POST表单对象

readonly_field 前端展示:

1.普通字段

2.一对多字段

3.多对对字段

Python CRM项目七的更多相关文章

  1. Python CRM项目二

    一.准备工作 如果没有配置基本的项目,请参考 http://www.cnblogs.com/luhuajun/p/7771196.html 当我们配置完成后首先准备我们的app 创建2个app分别对应 ...

  2. Python CRM项目八

    自定义用户认证 目的:实现Django自定义的认证系统,在生产环境都是根据此代码进行定制的 步骤: 1.在settings文件中配置要使用的类 #命名规则 app名称.类名 AUTH_USER_MOD ...

  3. Python CRM项目一

    开发环境: 语言Python3.X以上 MTV WEB框架 Django 前端框架 jQuery+bootstrap 数据库 MySQL 运行环境 安装Python3.x 安装Django 除IE8以 ...

  4. Python CRM项目三

    1.分页: 分页使用Django内置的分页模块来实现 官方的分页案例 from django.core.paginator import Paginator, EmptyPage, PageNotAn ...

  5. python实践项目七:正则表达式版本的strip()函数

    描述:写一个函数,它接受一个字符串,做的事情和 strip()字符串方法一样.如果只传入了要去除的字符串, 没有其他参数, 那么就从该字符串首尾去除空白字符:否则, 函数第二个参数指定的字符将从该字符 ...

  6. Python CRM项目六

    自定义Django Admin的action 在Django Admin中,可以通过action来自定义一些操作,其中默认的action的功能是选中多条数据来进行删除操作 我们在king_admin中 ...

  7. Python CRM项目四

    实现Django Admin的多对多的复选框效果 效果:左边显示的是未选中的字段,右边显示的是已选中的字段,两边点击的标签可以互相更换 首先在king_admin.py中增加filter_horizo ...

  8. CRM项目总结

                CRM项目总结      一:开发背景 在公司日益扩大的过程中,不可避免的会伴随着更多问题出现. 对外 : 如何更好的管理客户与公司的关系?如何更及时的了解客户日益发展的需求变 ...

  9. CRM项目之RBAC权限组件-day26

    写在前面 上课第26天,打卡: 世间安得双全法 不负如来不负卿 s17day26 CRM项目 项目概要:XX公司CRM - 权限管理,公共组件,app ***** - 熟悉增删改查,Low *** - ...

随机推荐

  1. 读书笔记《CSS权威指南》

    阅读本书主要目的: 自从学会CSS以来,虽然熟练掌握了其使用方法和技巧,但对其底层的原理和实现并不清晰,阅读本书想进一步系统化的学习和深入研究其本质,对这门前端基础语言从熟练使用到真正理解. 第1章 ...

  2. hdu_1041(Computer Transformation) 大数加法模板+找规律

    Computer Transformation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/ ...

  3. 让BLE设备的名称包含MAC地址

    对于研发和测试BLE来说,经常看到同名的设备,是极为不方便的,一大堆设备同时上电会让同事不知道哪一个设备才是自己真正想操作的目标.再说一下小米手环,家中有三支小米手环,打开设备搜索全是“MI”,都不知 ...

  4. Oracle:FOR循环语句练习

    --打印输出从1到10的正整数DECLARE v_i NUMBER(10) := 0;BEGIN LOOP v_i := v_i + 1; DBMS_OUTPUT.put_line(v_i); EXI ...

  5. maven项目 在eclipse,InteliJ IDEA中的一些问题

    转载请注明出处,谢谢! 不论我们用什么ide来编辑我们的代码,最终的产品都会脱离ide来运行:正如燕飞离了巢,正如你离开了家,不期然就会运转出现问题. - 单强 2018年1月26日11:53 大家是 ...

  6. 高级设置电脑系统windows7防火墙出错代码0×6D9原因与解决技巧

    高级设置windows防火墙能够更好的保护电脑系统安全,在电脑系统windows7设置过程中难免会遇到某些问题,有用户在安装MRGT后想要打开SNMP的161端口,但在打开高级安全windows防火墙 ...

  7. 机器学习——kNN(1)基本原理

    =================================版权声明================================= 版权声明:原创文章 禁止转载  请通过右侧公告中的“联系邮 ...

  8. C#编写街道管理系统

    项目需求: 一.语言和环境 A.实现语言 C# B.环境要求 Visual Studio 2012 二.功能要求 现使用.NET WinForms技术为居委会开发一个街道管理软件,其中街道管理窗体界面 ...

  9. 为什么要进行URL编码

    我们都知道Http协议中参数的传输是"key=value"这种简直对形式的,如果要传多个参数就需要用“&”符号对键值对进行分割.如"?name1=value1&a ...

  10. PostgreSql 分页limit

    摘录自:http://jingyan.baidu.com/article/a17d528538119b8098c8f2ca.html 语法: select * from persons limit   ...