类Xadmin插件--海豚插件

一款类似于xadmin的仿制Django内部admin管理的插件。用于系统开发。起个好听的名字。海豚插件。

 

 

from django.contrib import admin
from Dolphin.service.Dolphin import site,ModelDolphin
from django.shortcuts import HttpResponse,render,redirect,reverse
from django.utils.safestring import mark_safe
from ocas.models import *
from django.forms import ModelForm
# Register your models here.

class CompanyConfig(ModelDolphin):

    # def xxx(self,obj=None,header=False):
    #     if header:
    #         return "显示标题(可修改)"
    #     return 123

    list_display=('id','full_name','short_name','registered_capital',
                    'quality_management_system_certificate',"occupational_health_and_safety_system_certificate",
                    'environmental_management_system_certificate','staff_headcount','staff_productor_count','staff_main_network_engineer_count',
                  'b_city','qualifications'
                  )
    list_display_links = ("full_name",)
    search_fields = ('full_name',)
    list_per_page=5
    # def patch_init(self,request,queryset):
    #     print(queryset)
    # patch_init.short_description = "批量初始化"
    # actions = (patch_init,)

    list_filter = ('b_city','qualifications','using_software',)#

class StaffModelForm(ModelForm):
    class Meta:
        model=Staff
        fields="__all__"
        exclude=('is_delete',)


class StaffConfig(ModelDolphin):
    list_display = ('id','sjdw','user','gender','native_place',)
    modelform_class = StaffModelForm
    search_fields = ('user',)
    list_filter = ('sjdw',)

class SoftwareConfig(ModelDolphin):
    # list_display = ('id',)
    list_per_page = 5

site.register(Company,CompanyConfig)
site.register(Qualification)
site.register(Software,SoftwareConfig)
site.register(Vendor)
site.register(City)
site.register(Staff,StaffConfig)
site.register(UserInfo,)
# print(site._registry)

 

 

 

#!/usr/bin/env python3
#-*- coding:utf-8 -*-
'''
Administrator 
2019/2/20 
'''
from django.urls import include, path, re_path
from django.conf.urls import url
from django.shortcuts import HttpResponse,render,redirect,reverse
from django.utils.safestring import mark_safe
from collections import deque
from django.forms import ModelForm
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
import copy
from django.db.models import Q
from django.db.models.fields.related import ManyToManyField,ForeignKey
from django.forms.models import ModelMultipleChoiceField,ModelChoiceField
from django.forms.fields import BooleanField
# from Dolphin.service.dolform import ModelFormDemo
class ShowList(object):
    def __init__(self,config,data_list,request):
        self.config=config
        self.data_list=data_list
        self.request=request
        self.page_data=self.get_query_sets()
        #action
        self.actions=self.config.new_actions
    def get_action_list(self):
        temp=[]
        # print(self.actions)
        for func_obj in self.actions:
            temp.append({
                "name":func_obj.__name__,
                # "desc":func_obj.short_description
                # "desc":getattr(func_obj,"short_description",func_obj.__name__)
                "desc":func_obj.short_description if hasattr(func_obj, "short_description") else func_obj.__name__
            })
        return temp
    def get_header(self):
        # 构建表头数据
        header_list = []
        for filed in self.config.new_list_play():
            if callable(filed):
                # header_list.append(filed.__name__.upper())
                header_list.append(filed(self.config, header=True))
            elif filed == "__str__":
                header_list.append(self.config.model._meta.model_name.upper())
            else:
                header_list.append(self.config.model._meta.get_field(filed).verbose_name)
                # header_list.append(filed[:10].upper
        return header_list
    def get_body(self):
        new_data_list = []

        for obj in self.page_data:
            temp = []
            for field in self.config.new_list_play():
                if callable(field):
                    val = field(self.config, obj)
                else:
                    try:
                        field_obj=self.config.model._meta.get_field(field)
                        if isinstance(field_obj,ManyToManyField):
                            ret = getattr(obj, field).all()
                            t = []
                            for m2m_obj in ret:
                                t.append('''<span class='label label-primary'>{0}</span>'''.format(m2m_obj))
                            val=mark_safe('<br>'.join(t))
                        else:
                            val = getattr(obj, field)
                            if field in self.config.list_display_links:
                                _url = self.config.reverse_url("change", obj)
                                val = mark_safe("<a href={0}>{1}</a>".format(_url, val))
                    except Exception as e:
                        val = getattr(obj, field)
                        # if field in self.config.list_display_links:
                        #     _url = self.config.reverse_url("change", obj)
                        #     val = mark_safe("<a href={0}>{1}</a>".format(_url, val))

                temp.append(val)
            new_data_list.append(temp)
        return new_data_list
    def get_query_sets(self):
        paginator = Paginator(self.data_list, self.config.list_per_page)
        page = self.request.GET.get('page')
        try:
            query_sets = paginator.page(page)
        except PageNotAnInteger:
            query_sets = paginator.page(1)
        except EmptyPage:
            query_sets = paginator.page(paginator.num_pages)  # Paginator.num_pages:总共分页数
        return query_sets
    def new_pagination(self):
        params = copy.deepcopy(self.request.GET)  # {"page":"12","title_startwith":"py","id__gt":"5"}
        url_prefix = self.request.path#当前路径
        page_html=""
        added_dot_ele = False
        for page_num in self.page_data.paginator.page_range:
            params["page"] = page_num
            if page_num<3 or page_num>self.page_data.paginator.num_pages-2 \
                or abs(self.page_data.number-page_num)<=2:#代表前面两页和后面两页
                ele_class=""
                if self.page_data.number==page_num:
                    added_dot_ele=False
                    ele_class="active"
                page_html+='''<li class="{0}"><a href="{1}?{2}">{3}</a></li>'''.format(ele_class,url_prefix,params.urlencode(),page_num)
            else:
                if not added_dot_ele:
                    page_html += '<li><a>...</a></li>'
                    added_dot_ele = True

        if self.page_data.has_previous():
            params["page"] = self.page_data.previous_page_number()
            page_html='''<li><a href="{0}?{1}">«</a></li>'''.format(url_prefix,params.urlencode())+page_html
        else:
            page_html='''<li class="disabled" ><a href="javascript:void(0);">«</a></li>'''+page_html

        if self.page_data.has_next():
            params["page"] =self.page_data.next_page_number()
            page_html+='''<li><a href="{0}?{1}">»</a></li>'''.format(url_prefix,params.urlencode())
        else:
            page_html+='''<li class="disabled" ><a href="javascript:void(0);">»</a></li>'''
        return page_html
    def get_filter_linktags(self):
        link_list={}
        url_prefix = self.request.path  # 当前路径
        for filter_field in self.config.list_filter:
            params = copy.deepcopy(self.request.GET)
            cid=self.request.GET.get(filter_field,0)
            filter_field_obj=self.config.model._meta.get_field(filter_field)
            filter_field_verbose_name="以 {0}".format(filter_field_obj.verbose_name)
            if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):

                # data_list=filter_field_obj.rel.to.objects.all()  #django 1.0的用法
                data_list=filter_field_obj.related_model.objects.all()#django 2.0 的用法
            else:
                data_list=self.config.model.objects.values("pk",filter_field)
            temp=[]
            #处理 全部标签
            if params.get(filter_field):
                del params[filter_field]
                active = ""
            else:
                active = "active"
            temp.append('''<li class={0}><a href='{1}?{2}'>全部</a></li>'''.format(active,url_prefix,params.urlencode(),))
            for obj in data_list:
                if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                    pk=obj.pk
                    text=str(obj)
                    params[filter_field] = pk
                else:
                    pk=obj.get("pk")
                    text=obj.get(filter_field)
                    params[filter_field] = text
                if cid==str(pk) or cid==text:
                    active="active"
                else:
                    active=""
                    # params[filter_field]=pk
                a_ele = '''<li class={0}><a href='{1}?{2}'>{3}</a></li>'''.format(active,url_prefix,params.urlencode(),text)
                temp.append(a_ele)
            #
            link_list[filter_field_verbose_name]=temp
        return link_list

class ModelDolphin(object):

    list_display = ('__str__',)
    list_display_links = ()
    list_per_page=10#默认每页展示10行数据
    search_fields=()#关键词搜索
    actions=()#自定义字段
    list_filter=()#分组查询
    #用户可以自定义ModelForm
    modelform_class=None

    def __init__(self,model,site):
        self.model=model
        self.site=site
    def reverse_url(self,string,obj=None):
        app_label = self.model._meta.app_label
        model_name = self.model._meta.model_name
        if string in ["change","delete",]:
            _url = reverse("{app_label}_{model_name}_{action}".format(app_label=app_label, model_name=model_name,
                                                                      action=string),
                           args=(obj.pk,))
            return _url
        elif string in ["add","list"]:
            _url = reverse("{app_label}_{model_name}_{action}".format(app_label=app_label, model_name=model_name,
                                                                      action=string),)
            return _url
        else:
            raise AttributeError("参数有误,没有这个属性.只能使用 change/delete/add/list")
    def edit(self,obj=None,header=False):
        if header:
            return "编辑"
        app_label = self.model._meta.app_label
        model_name = self.model._meta.model_name
        # _url =reverse( "{app_label}_{model_name}_change".format(app_label=app_label, model_name=model_name),args=(obj.pk,))
        _url=self.reverse_url("change",obj)
        # return mark_safe("<a href='{0}/change'>编辑</a>".format(obj.pk))
        return mark_safe("<a href='{_url}'>编辑</a>".format(_url=_url,pk=obj.pk))

    def deletes(self,obj=None,header=False):
        if header:
            return "删除"
        # app_label = self.model._meta.app_label
        # model_name = self.model._meta.model_name
        # _url = reverse("{app_label}_{model_name}_delete".format(app_label=app_label, model_name=model_name),
        #                args=(obj.pk,))
        _url=self.reverse_url("delete",obj)
        return mark_safe('''<a href='{_url}'>删除</a>'''.format(_url=_url))
    def checkbox(self,obj=None,header=False):
        if header:
            return mark_safe("<input id='choice' type='checkbox'/>")
        return mark_safe("<input class='choice_item' type='checkbox' name='selected_pk' value='{val}'/>".format(val=obj.pk))

    def new_list_play(self):
        temp=[]
        temp.append(ModelDolphin.checkbox)
        temp.extend(self.list_display)
        if not self.list_display_links:
            temp.append(ModelDolphin.edit)
        temp.append(ModelDolphin.deletes)
        return temp
    def display_all_related_objs(self,objs):
        #objs=[objs,]
        ul_ele="<ul>"
        for obj in objs:
            li_ele='''<li>{0}:{1}</li>'''.format(obj._meta.verbose_name,obj.__str__().strip("<>"))
            ul_ele+=li_ele
            for m2m_field in obj._meta.local_many_to_many:
                sub_ul_ele="<ul>"
                m2m_field_obj=getattr(obj,m2m_field.name)
                for o in m2m_field_obj.select_related():
                    li_ele = '''<li>{0}:{1}</li>'''.format(m2m_field.verbose_name, o.__str__().strip("<>"))
                    sub_ul_ele+=li_ele
                sub_ul_ele+="</ul>"
                ul_ele+=sub_ul_ele
            for related_obj in obj._meta.related_objects:
                if 'ManyToManyRel' in related_obj.__repr__():

                    if hasattr(obj, related_obj.get_accessor_name()):  # hassattr(customer,'enrollment_set')
                        accessor_obj = getattr(obj, related_obj.get_accessor_name())
                        # print("-------ManyToManyRel", accessor_obj, related_obj.get_accessor_name())
                        # 上面accessor_obj 相当于 customer.enrollment_set
                        if hasattr(accessor_obj, 'select_related'):  # slect_related() == all()
                            target_objs = accessor_obj.select_related()  # .filter(**filter_coditions)
                            # target_objs 相当于 customer.enrollment_set.all()

                            sub_ul_ele = "<ul style='color:red'>"
                            for o in target_objs:
                                li_ele = '''<li> %s: %s </li>''' % (o._meta.verbose_name, o.__str__().strip("<>"))
                                sub_ul_ele += li_ele
                            sub_ul_ele += "</ul>"
                            ul_ele += sub_ul_ele

                elif hasattr(obj, related_obj.get_accessor_name()):  # hassattr(customer,'enrollment_set')
                    accessor_obj = getattr(obj, related_obj.get_accessor_name())
                    # 上面accessor_obj 相当于 customer.enrollment_set
                    if hasattr(accessor_obj, 'select_related'):  # slect_related() == all()
                        target_objs = accessor_obj.select_related()  # .filter(**filter_coditions)
                        # target_objs 相当于 customer.enrollment_set.all()
                    else:
                        print("one to one i guess:", accessor_obj)
                        target_objs = accessor_obj

                    if len(target_objs) > 0:
                        # print("\033[31;1mdeeper layer lookup -------\033[0m")
                        # nodes = recursive_related_objs_lookup(target_objs,model_name)

                        nodes = self.display_all_related_objs(target_objs)
                        ul_ele += nodes
        ul_ele += "</ul>"
        return ul_ele

    def batch_remove(self,request,queryset):
        queryset.delete()
        # relected_obj=self.display_all_related_objs(queryset)
        # # print(html_str)
        # return render(request,'dolphin/dol_delete.html',locals())
    batch_remove.short_description = "批量删除"
    @property
    def new_actions(self):
        temp=[]
        temp.append(ModelDolphin.batch_remove)
        temp.extend(self.actions)
        return temp
    def set_pop_tags(self,forms):
        for bfield in forms:
            if isinstance(bfield.field,ModelMultipleChoiceField) or isinstance(bfield.field,ModelChoiceField):
                bfield.is_pop=True
                #两种方式获取类  一对多 或者多对多 的关联表  模型
                # filter_field_obj = self.model._meta.get_field(bfield.name).related_model
                filter_field_obj=bfield.field.queryset.model
                # print("----",bfield.name,type(bfield.name),filter_field_obj)
                # print("+++++++++",filter_field_obj2)
                related_app_label = filter_field_obj._meta.app_label
                related_model_name = filter_field_obj._meta.model_name
                _url=reverse("{related_app_label}_{related_model_name}_add".format(related_app_label=related_app_label,
                                                                                   related_model_name=related_model_name))
                bfield.url=_url+"?pop_res_id={0}".format(bfield.auto_id )
            # if isinstance(bfield.field,BooleanField):
            #     print(bfield)
            #     bfield.is_checkbox=True
        return forms
    def get_modelform_class(self):
        if not self.modelform_class:
            class ModelFormDemo(ModelForm):
                class Meta:
                    model = self.model
                    fields = "__all__"
                    # exclude = ("is_delete",)
            return ModelFormDemo
        else:
            return self.modelform_class
    def get_search_condition(self,request):
        key_word = request.GET.get("key_words","")
        self.key_word=key_word
        # 获取当前列表中的所有数据

        search_connection = Q()
        search_connection.connector = "OR"
        for search_field in self.search_fields:
            search_connection.children.append(("{field}__contains".format(field=search_field), key_word))
        return search_connection
    def get_filter_condition(self,request):
        filter_condition = Q() #默认且
        for filter_field, val in request.GET.items():
            if filter_field in self.list_filter:
                filter_condition.children.append((filter_field, val))
        return filter_condition
    def list_view(self, request):
        if request.method=="POST":
            action= request.POST.get("action")
            selected_pk=request.POST.getlist("selected_pk")
            warning_flag=False
            if hasattr(self,action) and selected_pk:
                action_func=getattr(self,action)
                queryset = self.model.objects.filter(pk__in=selected_pk)
                action_func(request, queryset)
            else:
                warning_flag=True
        search_condition=self.get_search_condition(request)#获取  第一次关键词筛选的条件get("selected_pk")
        filter_condition=self.get_filter_condition(request)#获取  第二次过滤的条件
        # data_list=self.model.objects.all().filter(search_connection)#第一次筛选后的所有数据  通过关键词查询
        data_list = self.model.objects.get_queryset().filter(search_condition).filter(filter_condition)  # 解决异常 UnorderedObjectListWarning
        showlist=ShowList(self,data_list,request)
        #拿到表名
        tablename=self.model._meta.verbose_name_plural
        #构建一个添加数据连接
        add_url=self.reverse_url("add")

        return render(request, "dol_list.html", locals())#可以是 locals()

    def add_view(self, request):
        ModelFormDemo=self.get_modelform_class()
        list_url=self.reverse_url('list')
        forms =self.set_pop_tags(ModelFormDemo())


        if request.method=="POST":
            forms=self.set_pop_tags(ModelFormDemo(request.POST))

            if forms.is_valid():
                obj=forms.save()
                pop_res_id=request.GET.get("pop_res_id",None)
                if pop_res_id:
                    res={"pk":obj.pk,"text":str(obj),"pop_res_id":pop_res_id}

                    return render(request, "dol_pop.html", {"res":res})
                else:
                    return redirect(list_url)


        return render(request, "dol_add.html", locals())

    def change_view(self, request, id):

        ModelFormDemo = self.get_modelform_class()
        edit_obj=self.model.objects.filter(pk=id).first()
        list_url = self.reverse_url('list')
        if request.method=="POST":
            forms=ModelFormDemo(request.POST,instance=edit_obj)
            if forms.is_valid():
                forms.save()
                return redirect(list_url)
            return render(request, "dol_change.html", locals())
        forms = ModelFormDemo(instance=edit_obj)
        return render(request, "dol_change.html", locals())

    def delete_view(self, request, id):
        url_list = self.reverse_url('list')
        delete_obj=self.model.objects.filter(pk=id)
        print("####",delete_obj)

        if request.method=="POST":
            delete_obj.delete()
            return redirect(url_list)
        delete_obj_detail=self.display_all_related_objs(delete_obj)
        return render(request, "dol_delete.html", locals())

    @property
    def get_urls2(self):
        app_label = self.model._meta.app_label
        model_name = self.model._meta.model_name
        temp = []
        # print("#"*20)
        temp.append(re_path(r'^$', self.list_view,name="{app_label}_{model_name}_list".format(app_label=app_label,model_name=model_name)))
        temp.append(re_path(r'^add/$', self.add_view,name="{app_label}_{model_name}_add".format(app_label=app_label,model_name=model_name)))
        temp.append(re_path(r'^(\d+)/change/$', self.change_view,name="{app_label}_{model_name}_change".format(app_label=app_label,model_name=model_name)))
        temp.append(re_path(r'^(\d+)/delete/$', self.delete_view,name="{app_label}_{model_name}_delete".format(app_label=app_label,model_name=model_name)))

        return temp
    @property
    def urls2(self):
        return self.get_urls2, None, None
class DolphinSite(object):
    def __init__(self,name='admin'):
        self._registry={}

    def get_urls(self):
        temp=[]
        for model,dolphin_class_obj in self._registry.items():
            app_name=model._meta.app_label
            model_name=model._meta.model_name
            temp.append(path('{0}/{1}/'.format(app_name,model_name),dolphin_class_obj.urls2),)
        return temp
    @property
    def urls(self):
        return self.get_urls(),None,None
    def register(self, model, dolphin_class=None, **options):
        if not dolphin_class:
            dolphin_class=ModelDolphin
        self._registry[model] = dolphin_class(model, self)#放进字典里面

site=DolphinSite()
server.Dolphin.py

 

posted @ 2019-03-04 09:20  巨兽~墨菲特  阅读(361)  评论(0编辑  收藏  举报