CRM-stark组件

stark组件

1. stark也是一个app(用startapp stark创建),目标时把这个做成一个可以拔插的组件
2. setting文件下INSTALLED_APPS  路径要配置好(app的注册)
3. 写好sites.py中的site类,实例化出一个类对象,其他文件都直接引用这个类对象(单例模式),
4. 模型类和数据库也要确定好


from django.urls import path,re_path
from django.shortcuts import HttpResponse,render,redirect

from django.utils.safestring import mark_safe
from django.core.exceptions import FieldDoesNotExist
from django.urls import reverse
from django.db.models import Q
class ShowList(object):
    def __init__(self,request,config_obj,queryset):  #展示页面的自定制变量
        self.config_obj=config_obj
        self.queryset=queryset
        self.request=request
        self.pager_queryset=self.get_pager_queryset()  #分页

    def get_pager_queryset(self):  #分页功能

        from stark.utils.page import Pagination #一般是在stark组件下新建一个文件夹写好功能后直接倒过来
        current_page = self.request.GET.get("page", 1)
        self.pagination = Pagination(self.request, current_page, self.queryset, per_page_num=self.config_obj.per_page_num or 5)
        queryset = self.queryset[self.pagination.start:self.pagination.end]

        return queryset

    def get_header(self):
        '''
        获取表头
        :return:
        '''
        #   构建表头

        header_list = []
        for field_or_func in self.config_obj.get_new_list_display():
            if callable(field_or_func):
                val = field_or_func(self.config_obj, header=True)
                header_list.append(val)
                # header_list.append(field_or_func.__name__)
            else:
                if field_or_func == "__str__":
                    val = self.config_obj.model._meta.model_name.upper()
                    print(val)
                else:
                    field_obj = self.config_obj.model._meta.get_field(field_or_func)
                    val = field_obj.verbose_name
                header_list.append(val)

        return header_list

    def get_body(self):
        '''
        获取标体
        :return:
        '''
        #  构建展示数据
        new_data = []
        for obj in self.pager_queryset:
            temp = []

            for field_or_func in self.config_obj.get_new_list_display():  # ["title","price","state","publish",show_authors]
                if callable(field_or_func):
                    #  field:方法
                    val = field_or_func(self.config_obj, obj)
                else:
                    try:
                        #  field:字符串
                        from django.db.models.fields.related import ManyToManyField
                        field_obj = self.config_obj.model._meta.get_field(field_or_func)
                        #  判断是否多对多字段
                        if type(field_obj) == ManyToManyField:
                            raise Exception("list_display不能是多对多字段!")
                        #  判断字段是否 拥有choices属性
                        if field_obj.choices:
                            val = getattr(obj, "get_%s_display" % field_or_func)()
                        else:
                            val = getattr(obj, field_or_func)
                            if field_or_func in self.config_obj.list_display_links:
                                val = mark_safe("<a href='%s'>%s</a>" % (self.config_obj.get_change_url(obj), val))

                    except FieldDoesNotExist as e:
                        # val=obj
                        val = getattr(obj, field_or_func)()

                temp.append(val)
            new_data.append(temp)

        print("new_data", new_data)  # [['python', Decimal('123.00')], ['java', Decimal('234.00')]]

        '''
        目标数据结构
        new_data=[
            ["python",123],
            ["java",234]
        ]
        '''

        return new_data

class ModelStark(object):
    '''
    默认配置类
    '''
    list_display=("__str__",)
    list_display_links = []
    model_form_class=None
    per_page_num=None
    search_fields=[]
    search_val=None
    list_filter=[]
    list_title=None

    def __init__(self,model):
        self.model=model
        self.model_name = self.model._meta.model_name
        self.app_label = self.model._meta.app_label

    # 反向解析当前访问表的增删改查URL
    def get_list_url(self):
        # 反向解析当前表的删除的URL
        list_url = reverse("%s_%s_list" % (self.app_label, self.model_name))
        return list_url

    def get_add_url(self):
        # 反向解析当前表的删除的URL
        add_url = reverse("%s_%s_add" % (self.app_label, self.model_name))
        return add_url

    def get_delete_url(self,obj):
        # 反向解析当前表的删除的URL
        delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,))
        return delete_url

    def get_change_url(self, obj):
        # 反向解析当前表的删除的URL
        change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,))
        return change_url

    # 三个默认列
    def show_checkbox(self, obj=None, header=False):
        if header:
            return mark_safe("<input type='checkbox'>")
        return mark_safe("<input name='_selected_action' value=%s type='checkbox'>"%obj.pk)

    def show_delbtn(self, obj=None, header=False):
        if header:
            return "删除"

        return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj))

    def show_editbtn(self, obj=None, header=False):
        if header:
            return "编辑"
        return mark_safe("<a href='%s'>编辑</a>" %self.get_change_url(obj))

    #  构建新的list_display

    def get_new_list_display(self):
        temp=[]
        temp.extend(self.list_display)
        temp.append(ModelStark.show_editbtn)
        temp.append(ModelStark.show_delbtn)
        temp.insert(0,ModelStark.show_checkbox)

        return temp

    def get_search_condition(self,request):
        val = request.GET.get("q")


        q = Q()
        if val:
            self.search_val = val
            q.connector = "or"
            for field in self.search_fields:  # ["title","price"]
                print(field)
                # queryset=queryset.filter(Q(title__contains=val)|Q(price__contains=val))
                q.children.append((field + "__contains", val))
        else:
            self.search_val=None

        return q

    # action参数
    def patch_delete(self,request,queryset): # [1,3]
        queryset.delete()

    patch_delete.desc="批量删除"

    actions=[]
    def get_new_actions(self):
        temp=[]
        temp.extend(self.actions)
        temp.append(self.patch_delete)
        return temp

    def get_action_dict(self):
        actions_list=[]
        for func in self.get_new_actions():
            actions_list.append({
                "name":func.__name__,
                "desc":func.desc,
            })

        return actions_list   # [{"name":"patch_delete","desc":"批量删除"}]


    def get_list_filter_links(self):

        list_filter_links={}

        print(self.list_filter)  # ["publish","authors","state"]

        for filter_field in self.list_filter:
            import copy
            params = copy.deepcopy(self.request.GET)  # {"publish":1,"authors":1}
            current_field_val=params.get(filter_field)

            filter_field_obj=self.model._meta.get_field(filter_field)
            print(">>>",type(filter_field_obj))
            from django.db.models.fields.related import ForeignKey,ManyToManyField
            # 针对一对多或者多对多过滤字段
            if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
                # print("____>",filter_field_obj.remote_field.model) # <class 'app01.models.Publish'>
                # data=filter_field_obj.remote_field.model.objects.all()
                # print(data)
                rel_model = filter_field_obj.remote_field.model
                _limit_choices_to = filter_field_obj.remote_field.limit_choices_to
                data = rel_model.objects.filter(**_limit_choices_to)
            elif filter_field_obj.choices:
                # 针对choice字段类型
                data=filter_field_obj.choices # [(1,"已出版"),(2,"未出版社")]
            else:
                raise Exception("过滤字段不能太普通!")

            #  为每一个数据构建成一个a标签
            temp = []
            # params2=copy.deepcopy(params)
            if params.get(filter_field):
                del params[filter_field]

            all = "<a class='btn btn-default btn-sm' href='?%s'>全部</a>"%params.urlencode()
            temp.append(all)


            for item in data:
                if type(item)==tuple:
                    # 元组类型
                    pk,text = item
                else:
                    # model对象类型
                    pk,text = item.pk,str(item)

                params[filter_field]=pk            #  ***********
                _url="?%s"%(params.urlencode())    #  ***********

                if current_field_val==str(pk):
                     link="<a class='active btn btn-default btn-sm' href='%s'>%s</a>"%(_url,text)
                else:
                     link = "<a class='btn btn-default btn-sm' href='%s'>%s</a>" % (_url, text)

                temp.append(link)

            list_filter_links[filter_field]=temp

        return list_filter_links

    def get_list_filter_condition(self):

        q=Q()
        for filter_field,val in self.request.GET.items():
            if filter_field in ["page","q"]:continue
            q.children.append((filter_field,val))

        return q



    #  视图函数
    def list_view(self,request,querySet=None,flag=False):
        '''
        self: 当前访问模型表对应的配置类对象
        self.model: 当前访问模型表
        :param request:
        :return:
        '''
        self.request=request

        if request.method=="POST":
            #  action操作
            action_func_str=request.POST.get("action")
            if  action_func_str:
                action_func=getattr(self,action_func_str)
                _selected_action=request.POST.getlist("_selected_action") # [1,3]
                queryset=self.model.objects.filter(pk__in=_selected_action)
                action_func(request,queryset)


        if not flag:
            # print("self.model.__class__",self.__class__.__dict__)
            self.list_filter=self.__class__.__dict__.get("list_filter",[])
            self.actions=self.__class__.__dict__.get("actions",[])
            self.list_title=self.__class__.__dict__.get("list_title",[])
        if flag:
            queryset=querySet
        else:
            queryset=self.model.objects.all()

        # search过滤
        search_condition=self.get_search_condition(request)
        # list_filter多级过滤
        list_filter_condition=self.get_list_filter_condition()

        queryset=queryset.filter(search_condition).filter(list_filter_condition)

        show_list=ShowList(request,self,queryset)

        #  相关变量
        table_name=self.model._meta.verbose_name
        add_url=self.get_add_url()

        # # 获取登录人权限
        # print("Per:",request.session.get("permission_list"))
        # permission_list=request.session.get("permission_list")
        # menu_permissions=[]
        # for permission in  permission_list:
        #     if permission.get("type")=="button":continue
        #     menu_permissions.append(permission)

        import datetime
        now=datetime.datetime.now()

        title=self.list_title or "查看数据"
        return render(request,'stark/list_view.html',locals())

    def get_model_form(self):
        from django.forms import ModelForm
        class BaseModelForm(ModelForm):
            class Meta:
                model = self.model
                fields = "__all__"

        return self.model_form_class or BaseModelForm

    def add_view(self,request):
        BaseModelForm=self.get_model_form()

        if  request.method=="GET":
            form_obj=BaseModelForm()
            print(form_obj)
            return render(request,"stark/add_view.html",locals())
        else:
            form_obj = BaseModelForm(request.POST)
            if form_obj.is_valid():
                form_obj.save()
                return redirect(self.get_list_url())
            else:
                return render(request, "stark/add_view.html", locals())

    def change_view(self,request,id):
        BaseModelForm=self.get_model_form()
        edit_obj=self.model.objects.filter(pk=id).first()
        if  request.method=="GET":
            form_obj=BaseModelForm(instance=edit_obj)
            return render(request,"stark/change_view.html",locals())
        else:
            form_obj = BaseModelForm(request.POST,instance=edit_obj)
            if form_obj.is_valid():
                form_obj.save()
                return redirect(self.get_list_url())
            else:
                return render(request, "stark/change_view.html", locals())

    def delete_view(self,request, id):

        if request.method=="POST":
            self.model.objects.filter(pk=id).delete()
            return redirect(self.get_list_url())

        list_url=self.get_list_url()
        return render(request,"stark/delete_view.html",locals())

    def get_extra_url(self):

        return []

    @property
    def get_urls(self):

        temp = [
            path("", self.list_view,name="%s_%s_list"%(self.app_label,self.model_name)),
            path("add/", self.add_view,name="%s_%s_add"%(self.app_label,self.model_name)),
            re_path("(\d+)/change/", self.change_view,name="%s_%s_change"%(self.app_label,self.model_name)),
            re_path("(\d+)/delete/", self.delete_view,name="%s_%s_delete"%(self.app_label,self.model_name)),

        ]

        temp.extend(self.get_extra_url())
        return (temp, None, None)

class StarkSite:
    '''
    stark全局类
    '''
    def __init__(self):
        self._registry = {}

    def register(self, model, admin_class=None, **options):
        admin_class = admin_class or ModelStark
        self._registry[model] = admin_class(model)


    def get_urls(self):
        #  动态为注册的模型类创建增删改查URL
        temp = []
        # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)}
        for model, config_obj in self._registry.items():
            print("---->", model, config_obj)
            model_name = model._meta.model_name
            app_label = model._meta.app_label
            temp.append(
                path("%s/%s/" % (app_label,model_name),config_obj.get_urls)
            )

        '''
           path("stark/app01/book",BookConfig(Book).list_view)
           path("stark/app01/book/add",BookConfig(Book).add_view)      
           path("stark/app01/publish",ModelAdmin(Publish).list_view)
           path("stark/app01/publish/add",ModelAdmin(Publish).add_view)
        
        '''

        return temp

    @property
    def urls(self):
        return self.get_urls(),None,None

site = StarkSite()

猜你喜欢

转载自www.cnblogs.com/yang950718/p/10770937.html