zoukankan      html  css  js  c++  java
  • Python CRM项目七

    仿照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.多对对字段

  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/luhuajun/p/7890783.html
Copyright © 2011-2022 走看看