curd 插件

1. Django项目启动 自动加载文件 制作启动文件

1. 注册strak 在apps.py 类里面增加如下 

    def ready(self):
        from django.utils.module_loading import autodiscover_modules
        autodiscover_modules("stark")

2. 在已经注册的app中创建stark.py文件 加载
View Code

2. 在stark中模仿AdminSite ModelAdmin类写代码 注册自己的类

class StarkConfig(object):

    def __init__(self,model_class,site):
        self.model_class = model_class
        self.site = site


class StarkSite(object):

    def __init__(self):
        self._registey = {}

    def register(self,model_class,stark_config_class=None):
        if not stark_config_class:
            stark_config_class = StarkConfig

        self._registey[model_class] = stark_config_class(model_class,self)

site = StarkSite()
View Code

3. 将注册的类自动生成url

- urls.py
    from stark.service import v1

    urlpatterns = [
        url(r'^stark/', v1.site.urls),
    ]

- 为每个类生成4个url v1.py 
    
    class StarkConfig(object):

        def __init__(self,model_class,site):
            self.model_class = model_class
            self.site = site

        def get_urls(self):
            app_model_name = (self.model_class._meta.app_label,self.model_class._meta.model_name,)
            url_patterns = [
                url(r'^$',self.changelist_view,name="%s_%s_changlist" %app_model_name),
                url(r'^add/$',self.add_view,name="%s_%s_add" %app_model_name),
                url(r'^(d+)/delete/$',self.delete_view,name="%s_%s_delete" %app_model_name),
                url(r'^(d+)/change/$',self.change_view,name="%s_%s_chang" %app_model_name),
            ]
            return url_patterns

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

        def changelist_view(self,request,*args,**kwargs):
            return HttpResponse('列表')

        def add_view(self,request,*args,**kwargs):
            return HttpResponse('添加')

        def delete_view(self,request,nid,*args,**kwargs):
            return HttpResponse('删除')

        def change_view(self,request,nid,*args,**kwargs):
            return HttpResponse('修改')


    class StarkSite(object):

        def __init__(self):
            self._registey = {}

        def register(self,model_class,stark_config_class=None):
            if not stark_config_class:
                stark_config_class = StarkConfig

            self._registey[model_class] = stark_config_class(model_class,self)

        def get_urls(self):
            url_pattern = []

            for model_class,stark_config_obj in self._registry.items():
               
                app_name = model_class._meta.app_label
                model_name = model_class._meta.model_name

                curd_url = url(r'^%s/%s/' %(app_name,model_name,) , (stark_config_obj.urls,None,None))
                url_pattern.append(curd_url)

            return url_pattern


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


    site = StarkSite()
View Code

4. 列表页面展示 

- v1.py
    def changelist_view(self,request,*args,**kwargs):
    # 处理表头

    head_list = []
    for field_name in self.list_display:
        if isinstance(field_name,str):
            # 根据类和字段名称,获取字段对象的verbose_name
            verbose_name = self.model_class._meta.get_field(field_name).verbose_name
        else:
            verbose_name = field_name(self,is_header=True)
        head_list.append(verbose_name)

    # 处理表中的数据
    # [ UserInfoObj,UserInfoObj,UserInfoObj,UserInfoObj,]
    # [ UserInfo(id=1,name='alex',age=18),UserInfo(id=2,name='alex2',age=181),]
    data_list = self.model_class.objects.all()
    new_data_list = []
    for row in data_list:
        # row是 UserInfo(id=2,name='alex2',age=181)
        # row.id,row.name,row.age
        temp = []
        for field_name in self.list_display:
            if isinstance(field_name,str):
                val = getattr(row,field_name) # # 2 alex2
            else:
                val = field_name(self,row)
            temp.append(val)
        new_data_list.append(temp)

    return render(request,'stark/changelist.html',{'data_list':new_data_list,'head_list':head_list})

- shark.py
    class UserInfoConfig(v1.StarkConfig):

    def checkbox(self,obj=None,is_header=False):
        if is_header:
            return '选择'
        return mark_safe('<input type="checkbox" name="pk" value="%s" />' %(obj.id,))
    def edit(self,obj=None,is_header=False):
        if is_header:
            return '编辑'
        return mark_safe('<a href="/edit/%s">编辑</a>' %(obj.id,))

    list_display = [checkbox,'id','name',edit]
View Code

5. 显示增加按钮

- 先判断是否显示,再通过反向解析生成增加链接
- 后端
    # 是否显示增加按钮
    show_add_btn = True
    def get_show_btn(self):
        return self.show_add_btn

    return render(request, 'stark/changelist.html', {'data_list': new_data_list, 'head_list': head_list,"add_url":self.get_add_url(),"show_add_btn":self.get_show_bt
- 前端
    {% if show_add_btn %}
        <a class="btn btn-primary" href="{{ add_url }}">增加
    {% endif %}

6. 增加页面

增加内容页面

    1. 通过ModelForm创建公共类 显示和提交

        - 后端

            def add_view(self, request, *args, **kwargs):

                class AddTable(ModelForm):
                    class Meta:
                        model = self.model_class
                        fields = "__all__"

                if request.method == "GET":
                    form = AddTable()
                    return render(request,"stark/add_view.html",{"form":form})
                else:
                    form = AddTable(request.POST)
                    if form.is_valid():
                        form.save()
                        return redirect(self.get_list_url())
                    else:
                        return render(request, "stark/add_view.html", {"form": form})

        - 前端
            <form method="post" novalidate>
                {% csrf_token %}
                {{ form.as_p }}
                <input type="submit" value="提交">
            </form>

    2. 升级 在子类自定义ModelForm类 子类之后可以自定义类

        - v1.py
            model_form_class = None
                def get_model_form_class(self):
                    if self.model_form_class:
                        return self.model_form_class
                    else:
                        #方式一:
                        # class AddTable(ModelForm):
                        #     class Meta:
                        #         model = self.model_class
                        #         fields = "__all__"
                        # return AddTable
                        #方式二:
                        meta = type("Meta",(object,),{"model":self.model_class,"fields":"__all__"})
                        AddTable = type("AddTable",(ModelForm,),{"Meta":meta})
                        return AddTable


            def add_view(self, request, *args, **kwargs):
                model_form_class = self.get_model_form_class()
                if request.method == "GET":
                    form = model_form_class()
                    return render(request,"stark/add_view.html",{"form":form})
                else:
                    form = model_form_class(request.POST)
                    if form.is_valid():
                        form.save()
                        return redirect(self.get_list_url())
                    else:
                        return render(request, "stark/add_view.html", {"form": form})
        - stark.py

            class UserInfoModelForm(ModelForm):
                class Meta:
                    model = models.UserInfo
                    fields = ["name","password"]
                    error_messages = {
                        "name":{
                            'required':'用户名不能为空'
                        }
                    }
            class UserInfoConfig(v1.StarkConfig):
                model_form_class = UserInfoModelForm
View Code

9. 修改 删除 

def change_view(self, request, nid, *args, **kwargs):

    obj = self.model_class.objects.filter(pk=nid).first()
    if not obj:
        return redirect(self.get_list_url())
    model_form_class = self.get_model_form_class()
    if request.method == "GET":
        form = model_form_class(instance=obj)
        return render(request,"stark/change_view.html",{"form":form})
    else:
        form = model_form_class(instance=obj,data=request.POST)
        if form.is_valid:
            form.save()
            return redirect(self.get_list_url())
        return render(request,"stark/change_view.html",{"form":form})

def delete_view(self, request, nid, *args, **kwargs):
    self.model_class.objects.filter(pk=nid).delete()
    return redirect(self.get_list_url())
View Code

10. 组合搜索

阶段一:

阶段一:
    
    - 派生类
        # 三个条件分别为 choice  M2M FK
        comb_filter = ["gender","depart","roles"]

    - 基类

        comb_filter = []
        def get_comb_filter(self):
            return self.comb_filter

    - ChangeList 初始化
        self.comb_filter = config.get_comb_filter()

        from django.db.models import ForeignKey,ManyToManyField
            # 根据列表的字符串找到数据的字段对象,判断对象是否是FK,M2M
            # 如果不是 为chioce
            def gen_comb_filter(self):
                data_list = []
                for item in self.comb_filter:
                    # item    gender
                    _field = self.model_class._meta.get_field(item)
                    # _field  app04.UserInfo.gender
                    if isinstance(_field,ForeignKey):
                        #如果字段的类型是ForeignKey 找到他对应的类和数据
                        data_list.append(_field.rel.to.objects.all())
                    elif isinstance(_field,ManyToManyField):
                        data_list.append(_field.rel.to.objects.all())
                    else:
                        #choice
                        data_list.append(_field.choices)
                return data_list


    - 前端
    
        <div>
            {% for comb in self.gen_comb_filter %}
                <div>
                    {% for item in comb %}
                        <a href="">{{ item }}</a>
                    {% endfor %}
                </div>
            {% endfor %}
        </div>
View Code

阶段二:  用户查找的数据封装到类里面  前端循环 和上面效果一样

    class FilterRow(object):

        def __init__(self,data):
            self.data = data

        def __iter__(self):
            yield "全部"
            for val in self.data:
                yield val

    def gen_comb_filter(self):
        data_list = []
        for item in self.comb_filter:
            # item    gender
            _field = self.model_class._meta.get_field(item)
            # _field  app04.UserInfo.gender
            if isinstance(_field,ForeignKey):
                #如果字段的类型是ForeignKey 找到他对应的类和数据
                data_list.append(FilterRow(_field.rel.to.objects.all()))
            elif isinstance(_field,ManyToManyField):
                data_list.append(FilterRow(_field.rel.to.objects.all()))
            else:
                #choice
                data_list.append(FilterRow(_field.choices))
        return data_list
View Code

阶段三: 增加搜索条件可以为多选  封装到类里面判断

        comb_filter = [
            v1.filterOption("gender"),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]

        class filterOption(object):
            def __init__(self,filed_name,muti=False):
                self.filed_name = filed_name
                self.muti = muti

        def gen_comb_filter(self):
            data_list = []
            for obj in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(obj.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    data_list.append(FilterRow(_field.rel.to.objects.all()))
                elif isinstance(_field,ManyToManyField):
                    data_list.append(FilterRow(_field.rel.to.objects.all()))
                else:
                    #choice
                    data_list.append(FilterRow(_field.choices))
            return data_list
View Code

阶段四: 搜索条件自定义  效果如上

好处1: 如部门表有 销售部门 运维部门 开发部门  默认只让显示 销售部门和运维部门
好处2: 可以继承filterOption类 重写filterOption类底下的两个方法 
        comb_filter = [
            v1.filterOption("gender"),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]


        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False):
                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition

            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()
                return _field.rel.to.objects.all()


            def get_choices(self,_field):
               return _field.choices


        class FilterRow(object):
            def __init__(self,data):
                self.data = data
            def __iter__(self):
                yield "全部"
                for val in self.data:
                    yield val


        def gen_comb_filter(self):
            data_list = []
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option.get_queryset(_field))
                    data_list.append(row)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option.get_queryset(_field))
                    data_list.append(row)
                else:
                    #choice
                    row = FilterRow(option.get_choices(_field))
                    data_list.append(row)
            return data_list
View Code

阶段五:  返回列表变为生成器

 comb_filter = [
            v1.filterOption("gender"),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]


        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False):
                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition

            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()
                return _field.rel.to.objects.all()


            def get_choices(self,_field):
               return _field.choices


        class FilterRow(object):
            def __init__(self,data):
                self.data = data
            def __iter__(self):
                yield "全部"
                for val in self.data:
                    yield val



    def gen_comb_filter(self):
        for option in self.comb_filter:
            # item    gender
            _field = self.model_class._meta.get_field(option.filed_name)
            # _field  app04.UserInfo.gender
            if isinstance(_field,ForeignKey):
                #如果字段的类型是ForeignKey 找到他对应的类和数据
                row = FilterRow(option.get_queryset(_field))
            elif isinstance(_field,ManyToManyField):
                row = FilterRow(option.get_queryset(_field))
            else:
                #choice
                row = FilterRow(option.get_choices(_field))
            yield row
View Code

阶段六: 前端循环时 如果是choice根据索引取值 如果是对象 根据对象的方法取值 所以需要做出区分 并且在后端生成url 全部的a标签还未做 

    comb_filter = [
        v1.filterOption("gender",is_choice=True),
        v1.filterOption("depart"),
        v1.filterOption("roles",True)
    ]

    class filterOption(object):
        def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
            """

            :param filed_name:
            :param muti:
            :param condition: 过滤条件
            """

            self.filed_name = filed_name
            self.muti = muti
            self.condition = condition
            self.is_choice = is_choice

        def get_queryset(self,_field):
            if self.condition:
                return _field.rel.to.objects.filter()

            return _field.rel.to.objects.all()

        def get_choices(self,_field):

           return _field.choices



    class FilterRow(object):

        def __init__(self,option,data,params):
            self.option = option
            self.data = data
            self.params = copy.deepcopy(params)

        def __iter__(self):
            yield mark_safe("<a href={0}>全部</a>".format("111"))
            for val in self.data:
                if self.option.is_choice:
                    pk,text = val
                else:
                    pk,text = val.pk,str(val)
                yield mark_safe("<a href={0}>{1}</a>".format(pk,text))


    def gen_comb_filter(self):
        for option in self.comb_filter:
            # item    gender
            _field = self.model_class._meta.get_field(option.filed_name)
            # _field  app04.UserInfo.gender
            if isinstance(_field,ForeignKey):
                #如果字段的类型是ForeignKey 找到他对应的类和数据
                row = FilterRow(option,option.get_queryset(_field),self.request.GET)
            elif isinstance(_field,ManyToManyField):
                row = FilterRow(option,option.get_queryset(_field),self.request.GET)
            else:
                #choice
                row = FilterRow(option,option.get_choices(_field),self.request.GET)
            yield row
View Code

阶段七: 后端生成url 全部未做

        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
                """

                :param filed_name:
                :param muti:
                :param condition: 过滤条件
                """

                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition
                self.is_choice = is_choice


            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()

                return _field.rel.to.objects.all()


            def get_choices(self,_field):

               return _field.choices


        class FilterRow(object):

            def __init__(self,option,data,request):
                self.option = option
                self.data = data
                self.request = request

            def __iter__(self):
                params = copy.deepcopy(self.request.GET)
                params._mutable = True

                yield mark_safe("<a href={0}>全部</a>".format("111"))
                for val in self.data:
                    if self.option.is_choice:
                        pk,text = val
                    else:
                        pk,text = val.pk,str(val)

                    params[self.option.filed_name] = pk
                    url = "%s?%s"%(self.request.path_info,params.urlencode())


                    yield mark_safe("<a href={0}>{1}</a>".format(url,text))


        def gen_comb_filter(self):
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                else:
                    #choice
                    row = FilterRow(option,option.get_choices(_field),self.request)
                yield row
View Code

阶段八: 请求的值如果和循环的值如果相同  全部和其它按钮 都判断

        comb_filter = [
            v1.filterOption("gender",is_choice=True),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]



        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
                """

                :param filed_name:
                :param muti:
                :param condition: 过滤条件
                """

                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition
                self.is_choice = is_choice


            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()

                return _field.rel.to.objects.all()


            def get_choices(self,_field):

               return _field.choices


        class FilterRow(object):

            def __init__(self,option,data,request):
                self.option = option
                self.data = data
                self.request = request

            def __iter__(self):
                params = copy.deepcopy(self.request.GET)
                params._mutable = True
                current_id = params.get(self.option.filed_name)

                # 如果循环的值 在前端传过来的里面 删除 
                if self.option.filed_name in params:
                    del params[self.option.filed_name]
                    url = "{0}{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}">全部</a>'.format(url))
                else:
                    url = "{0}{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}" class="active">全部</a>'.format(url))

                for val in self.data:
                    if self.option.is_choice:
                        pk,text = str(val[0]),str(val[1])
                    else:
                        pk,text = str(val.pk),str(val)

                    params[self.option.filed_name] = pk
                    url = "%s?%s"%(self.request.path_info,params.urlencode())

                    if current_id == pk:
                        yield mark_safe("<a href={0} class='active'>{1}</a>".format(url, text))
                    else:
                        yield mark_safe("<a href={0}>{1}</a>".format(url,text))

        
        def gen_comb_filter(self):
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                else:
                    #choice
                    row = FilterRow(option,option.get_choices(_field),self.request)
                yield row
View Code

阶段九: 单选前后台完成 

        # 组合搜索过滤
        comb_codition = {}
        option_list = self.get_comb_filter()
        flag = False
        for key in request.GET.keys():
            value_list = request.GET.getlist(key)
            for option in option_list:
                if option.filed_name == key:
                    flag = True
                    print("111")
                    break
            if flag:
                print("22")
                comb_codition["%s__in"%key] = value_list
        print(comb_codition)


        queryset = self.model_class.objects.filter(self.get_search_condition()).filter(**comb_codition)
View Code

阶段十  多选完成

    class filterOption(object):
        def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
            """

            :param filed_name:
            :param muti:
            :param condition: 过滤条件
            """

            self.filed_name = filed_name
            self.muti = muti
            self.condition = condition
            self.is_choice = is_choice


        def get_queryset(self,_field):
            if self.condition:
                return _field.rel.to.objects.filter()

            return _field.rel.to.objects.all()


        def get_choices(self,_field):

           return _field.choices


        class FilterRow(object):

            def __init__(self,option,data,request):
                self.option = option
                self.data = data
                self.request = request

            def __iter__(self):
                params = copy.deepcopy(self.request.GET)

                params._mutable = True
                current_id = params.get(self.option.filed_name)
                current_id_list = params.getlist(self.option.filed_name)

                # 全部  如果循环的值 在前端传过来的里面 删除
                if self.option.filed_name in params:
                    origin_list = params.pop(self.option.filed_name)
                    url = "{0}?{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}">全部</a>'.format(url))
                    params.setlist(self.option.filed_name,origin_list)
                else:
                    url = "{0}?{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}" class="active">全部</a>'.format(url))

                # 全部 后面的值
                for val in self.data:
                    if self.option.is_choice:
                        pk,text = str(val[0]),str(val[1])
                    else:
                        pk,text = str(val.pk),str(val)
                    if not self.option.muti:
                        # 单选
                        params[self.option.filed_name] = pk
                        url = "%s?%s"%(self.request.path_info,params.urlencode())

                        if current_id == pk:
                            yield mark_safe("<a href={0} class='active'>{1}</a>".format(url, text))
                        else:
                            yield mark_safe("<a href={0}>{1}</a>".format(url,text))
                    else:
                        # 多选
                        _params = copy.deepcopy(params)
                        id_list = params.getlist(self.option.filed_name)
                        if pk in current_id_list:

                            id_list.remove(pk)
                            _params.setlist(self.option.filed_name, id_list)
                            url = "%s?%s" % (self.request.path_info, _params.urlencode())
                            yield mark_safe("<a href={0} class='active'>{1}</a>".format(url, text))
                        else:

                            id_list.append(pk)
                            _params.setlist(self.option.filed_name,id_list)
                            url = "%s?%s" % (self.request.path_info, _params.urlencode())
                            yield mark_safe("<a href={0}>{1}</a>".format(url, text))


        queryset = self.model_class.objects.filter(self.get_search_condition()).filter(**comb_codition).distinct()
View Code
阶段一:
    
    - 派生类
        # 三个条件分别为 choice  M2M FK
        comb_filter = ["gender","depart","roles"]

    - 基类

        comb_filter = []
        def get_comb_filter(self):
            return self.comb_filter

    - ChangeList 初始化
        self.comb_filter = config.get_comb_filter()

        from django.db.models import ForeignKey,ManyToManyField
            # 根据列表的字符串找到数据的字段对象,判断对象是否是FK,M2M
            # 如果不是 为chioce
            def gen_comb_filter(self):
                data_list = []
                [
                    ((1,男),(2,女)),
                    [obj,obj,obj,obj],
                    [obj,obj,obj,obj]
                ]
                for item in self.comb_filter:
                    # item    gender
                    _field = self.model_class._meta.get_field(item)
                    # _field  app04.UserInfo.gender
                    if isinstance(_field,ForeignKey):
                        #如果字段的类型是ForeignKey 找到他对应的类和数据
                        data_list.append(_field.rel.to.objects.all())
                    elif isinstance(_field,ManyToManyField):
                        data_list.append(_field.rel.to.objects.all())
                    else:
                        #choice
                        data_list.append(_field.choices)
                return data_list


    - 前端

        <div>
            {% for comb in self.gen_comb_filter %}
                <div>
                    {% for item in comb %}
                        <a href="">{{ item }}</a>
                    {% endfor %}
                </div>
            {% endfor %}
        </div>



阶段二:    用户查找的数据封装到类里面  前端循环 和上面效果一样


    class FilterRow(object):

        def __init__(self,data):
            self.data = data

        def __iter__(self):
            yield "全部"
            for val in self.data:
                yield val

    def gen_comb_filter(self):
        data_list = []
        for item in self.comb_filter:
            # item    gender
            _field = self.model_class._meta.get_field(item)
            # _field  app04.UserInfo.gender
            if isinstance(_field,ForeignKey):
                #如果字段的类型是ForeignKey 找到他对应的类和数据
                data_list.append(FilterRow(_field.rel.to.objects.all()))
            elif isinstance(_field,ManyToManyField):
                data_list.append(FilterRow(_field.rel.to.objects.all()))
            else:
                #choice
                data_list.append(FilterRow(_field.choices))
        return data_list


阶段三:    搜索条件可以为多选  封装到类里面判断
    
        
    comb_filter = [
        v1.filterOption("gender"),
        v1.filterOption("depart"),
        v1.filterOption("roles",True)
    ]

    class filterOption(object):
        def __init__(self,filed_name,muti=False):
            self.filed_name = filed_name
            self.muti = muti

    def gen_comb_filter(self):
        data_list = []
        for obj in self.comb_filter:
            # item    gender
            _field = self.model_class._meta.get_field(obj.filed_name)
            # _field  app04.UserInfo.gender
            if isinstance(_field,ForeignKey):
                #如果字段的类型是ForeignKey 找到他对应的类和数据
                data_list.append(FilterRow(_field.rel.to.objects.all()))
            elif isinstance(_field,ManyToManyField):
                data_list.append(FilterRow(_field.rel.to.objects.all()))
            else:
                #choice
                data_list.append(FilterRow(_field.choices))
        return data_list


阶段四: 搜索条件自定义 
        好处1: 如部门表有 销售部门 运维部门 开发部门  默认只让显示 销售部门和运维部门
        好处2: 可以继承filterOption类 重写filterOption类底下的两个方法

        comb_filter = [
            v1.filterOption("gender"),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]


        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False):
                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition

            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()
                return _field.rel.to.objects.all()


            def get_choices(self,_field):
               return _field.choices


        class FilterRow(object):
            def __init__(self,data):
                self.data = data
            def __iter__(self):
                yield "全部"
                for val in self.data:
                    yield val


        def gen_comb_filter(self):
            data_list = []
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option.get_queryset(_field))
                    data_list.append(row)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option.get_queryset(_field))
                    data_list.append(row)
                else:
                    #choice
                    row = FilterRow(option.get_choices(_field))
                    data_list.append(row)
            return data_list


阶段六: 前端循环时 如果是choice根据索引取值 如果是对象 根据对象的方法取值 所以需要做出区分 并且在后端生成url 全部的a标签还未做


        comb_filter = [
            v1.filterOption("gender",is_choice=True),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]

        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
                """

                :param filed_name:
                :param muti:
                :param condition: 过滤条件
                """

                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition
                self.is_choice = is_choice

            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()

                return _field.rel.to.objects.all()

            def get_choices(self,_field):

               return _field.choices



        class FilterRow(object):

            def __init__(self,option,data,params):
                self.option = option
                self.data = data
                self.params = copy.deepcopy(params)

            def __iter__(self):
                yield mark_safe("<a href={0}>全部</a>".format("111"))
                for val in self.data:
                    if self.option.is_choice:
                        pk,text = val
                    else:
                        pk,text = val.pk,str(val)
                    yield mark_safe("<a href={0}>{1}</a>".format(pk,text))


        def gen_comb_filter(self):
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option,option.get_queryset(_field),self.request.GET)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option,option.get_queryset(_field),self.request.GET)
                else:
                    #choice
                    row = FilterRow(option,option.get_choices(_field),self.request.GET)
                yield row



阶段七: 后端生成url 全部未做 
    
        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
                """

                :param filed_name:
                :param muti:
                :param condition: 过滤条件
                """

                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition
                self.is_choice = is_choice


            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()

                return _field.rel.to.objects.all()


            def get_choices(self,_field):

               return _field.choices


        class FilterRow(object):

            def __init__(self,option,data,request):
                self.option = option
                self.data = data
                self.request = request

            def __iter__(self):
                params = copy.deepcopy(self.request.GET)
                params._mutable = True

                yield mark_safe("<a href={0}>全部</a>".format("111"))
                for val in self.data:
                    if self.option.is_choice:
                        pk,text = val
                    else:
                        pk,text = val.pk,str(val)

                    params[self.option.filed_name] = pk
                    url = "%s?%s"%(self.request.path_info,params.urlencode())


                    yield mark_safe("<a href={0}>{1}</a>".format(url,text))


        def gen_comb_filter(self):
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                else:
                    #choice
                    row = FilterRow(option,option.get_choices(_field),self.request)
                yield row


阶段八 请求的值如果和循环的值如果相同  全部和其它按钮 都判断 



        comb_filter = [
            v1.filterOption("gender",is_choice=True),
            v1.filterOption("depart"),
            v1.filterOption("roles",True)
        ]



        class filterOption(object):
            def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
                """

                :param filed_name:
                :param muti:
                :param condition: 过滤条件
                """

                self.filed_name = filed_name
                self.muti = muti
                self.condition = condition
                self.is_choice = is_choice


            def get_queryset(self,_field):
                if self.condition:
                    return _field.rel.to.objects.filter()

                return _field.rel.to.objects.all()


            def get_choices(self,_field):

               return _field.choices


        class FilterRow(object):

            def __init__(self,option,data,request):
                self.option = option
                self.data = data
                self.request = request

            def __iter__(self):
                params = copy.deepcopy(self.request.GET)
                params._mutable = True
                current_id = params.get(self.option.filed_name)

                # 如果循环的值 在前端传过来的里面 删除 
                if self.option.filed_name in params:
                    del params[self.option.filed_name]
                    url = "{0}{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}">全部</a>'.format(url))
                else:
                    url = "{0}{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}" class="active">全部</a>'.format(url))

                for val in self.data:
                    if self.option.is_choice:
                        pk,text = str(val[0]),str(val[1])
                    else:
                        pk,text = str(val.pk),str(val)

                    params[self.option.filed_name] = pk
                    url = "%s?%s"%(self.request.path_info,params.urlencode())

                    if current_id == pk:
                        yield mark_safe("<a href={0} class='active'>{1}</a>".format(url, text))
                    else:
                        yield mark_safe("<a href={0}>{1}</a>".format(url,text))

        
        def gen_comb_filter(self):
            for option in self.comb_filter:
                # item    gender
                _field = self.model_class._meta.get_field(option.filed_name)
                # _field  app04.UserInfo.gender
                if isinstance(_field,ForeignKey):
                    #如果字段的类型是ForeignKey 找到他对应的类和数据
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                elif isinstance(_field,ManyToManyField):
                    row = FilterRow(option,option.get_queryset(_field),self.request)
                else:
                    #choice
                    row = FilterRow(option,option.get_choices(_field),self.request)
                yield row


阶段九  单选完成


        # 组合搜索过滤
        comb_codition = {}
        option_list = self.get_comb_filter()
        flag = False
        for key in request.GET.keys():
            value_list = request.GET.getlist(key)
            for option in option_list:
                if option.filed_name == key:
                    flag = True
                    print("111")
                    break
            if flag:
                print("22")
                comb_codition["%s__in"%key] = value_list
        print(comb_codition)


        queryset = self.model_class.objects.filter(self.get_search_condition()).filter(**comb_codition)


阶段十  多选完成
    
    class filterOption(object):
        def __init__(self,filed_name,muti=False,condition=False,is_choice=False):
            """

            :param filed_name:
            :param muti:
            :param condition: 过滤条件
            """

            self.filed_name = filed_name
            self.muti = muti
            self.condition = condition
            self.is_choice = is_choice


        def get_queryset(self,_field):
            if self.condition:
                return _field.rel.to.objects.filter()

            return _field.rel.to.objects.all()


        def get_choices(self,_field):

           return _field.choices


        class FilterRow(object):

            def __init__(self,option,data,request):
                self.option = option
                self.data = data
                self.request = request

            def __iter__(self):
                params = copy.deepcopy(self.request.GET)

                params._mutable = True
                current_id = params.get(self.option.filed_name)
                current_id_list = params.getlist(self.option.filed_name)

                # 全部  如果循环的值 在前端传过来的里面 删除
                if self.option.filed_name in params:
                    origin_list = params.pop(self.option.filed_name)
                    url = "{0}?{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}">全部</a>'.format(url))
                    params.setlist(self.option.filed_name,origin_list)
                else:
                    url = "{0}?{1}".format(self.request.path_info, params.urlencode())
                    yield mark_safe('<a href="{0}" class="active">全部</a>'.format(url))

                # 全部 后面的值
                for val in self.data:
                    if self.option.is_choice:
                        pk,text = str(val[0]),str(val[1])
                    else:
                        pk,text = str(val.pk),str(val)
                    if not self.option.muti:
                        # 单选
                        params[self.option.filed_name] = pk
                        url = "%s?%s"%(self.request.path_info,params.urlencode())

                        if current_id == pk:
                            yield mark_safe("<a href={0} class='active'>{1}</a>".format(url, text))
                        else:
                            yield mark_safe("<a href={0}>{1}</a>".format(url,text))
                    else:
                        # 多选
                        _params = copy.deepcopy(params)
                        id_list = params.getlist(self.option.filed_name)
                        if pk in current_id_list:

                            id_list.remove(pk)
                            _params.setlist(self.option.filed_name, id_list)
                            url = "%s?%s" % (self.request.path_info, _params.urlencode())
                            yield mark_safe("<a href={0} class='active'>{1}</a>".format(url, text))
                        else:

                            id_list.append(pk)
                            _params.setlist(self.option.filed_name,id_list)
                            url = "%s?%s" % (self.request.path_info, _params.urlencode())
                            yield mark_safe("<a href={0}>{1}</a>".format(url, text))


        queryset = self.model_class.objects.filter(self.get_search_condition()).filter(**comb_codition).distinct()
组合筛选

11. popup

阶段一: 对于多选或单选 在后面增加popup按钮 其余不加

    - 在后端生成返回给前端
    - 如果是field是ModelChoiceField 则是Fk, 如果是ModelMultipChoice 则是M2M
    - GET请求 循环form,打印各个字段的类型 发现类型都为 <class 'django.forms.boundfield.BoundField'> 它是对字段的一次封装

        def add_view(self, request, *args, **kwargs):

            model_form_class = self.get_model_form_class()
            if request.method == "GET":
                form = model_form_class()
                """
                for field in form:
                    print(type(field))

                   <class 'django.forms.boundfield.BoundField'>
                """
                return render(request, "stark/add_view.html", {"form": form})
            else:
                form = model_form_class(request.POST)
                if form.is_valid():
                    form.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/add_view.html", {"form": form})
    
    - 在 BoundField类里面再找一个field属性 九可以找到每个类的属性  最后三个类都为ModelChoiceField的子类

        """   
        for bfield in form:
            print(type(bfield.field))

        <class 'django.forms.fields.CharField'>
        <class 'django.forms.fields.CharField'>
        <class 'django.forms.fields.TypedChoiceField'>
        <class 'django.forms.models.ModelChoiceField'>
        <class 'django.forms.models.ModelMultipleChoiceField'>
        """
说明
    - 后台代码
        def add_view(self, request, *args, **kwargs):

            model_form_class = self.get_model_form_class()
            if request.method == "GET":
                form = model_form_class()
                from django.forms import ModelChoiceField
                new_choice = []
                for bfield in form:
                    tmp = {"is_popup":False,"item":bfield}
                    if isinstance(bfield.field,ModelChoiceField):
                        tmp["is_popup"] = True
                    new_choice.append(tmp)

                return render(request, "stark/add_view.html", {"form": new_choice})
            else:
                form = model_form_class(request.POST)
                if form.is_valid():
                    form.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request, "stark/add_view.html", {"form": form})
    - 前端
        {% for dic in form %}
          <div class="form-group">
            <label for="inputEmail3" class="col-sm-2 control-label">{{ dic.label }}</label>
            <div class="col-sm-10" style="position: relative">
              {{ dic.item }}
              {% if dic.is_popup %}
                  <div style="position: absolute;right: -8px;top: 10px;">
                    <a class="glyphicon glyphicon-search" aria-hidden="true"></a>
                  </div>
              {% endif %}
              {{ dic.item.errors.0 }}
            </div>
          </div>
        {% endfor %}
代码

阶段二: 实现popup 

<form method="post"  class="form-horizontal" novalidate>
    {% csrf_token %}
    {% for dic in form %}
        <div class="col-sm-6">
            <div class="form-group" style="margin-bottom: 20px;">
                <label for="inputEmail3" class="col-sm-2 control-label">{{ dic.item.field.label }}</label>
                <div class="col-sm-10" style="position: relative">
                    <!-- 判断,如果field是ModelChoiceField,则FK; 如果是ModelMultipleChoiceField,则M2M -->
                    {{ dic.item }}
                    {% if dic.is_popup %}
                        <div style="position: absolute;right: -8px;top: 10px;">
                            <a onclick="popUp('{{ dic.popup_url }}')" class="glyphicon glyphicon-search"></a>
                        </div>
                    {% endif %}
                    <div style="position: absolute;font-size: 12px;left: 15px; right: 15px;color: #e4393c;background: #FFEBEB;">{{ dic.item.errors.0 }}</div>
                </div>
            </div>
        </div>
    {% endfor %}
    <div class="col-sm-offset-11 col-sm-1">
        <input type="submit" class="btn btn-primary" value="提交">
    </div>
</form>
<script>
    function popupCallback(dic) {
        var op = document.createElement('option');
        op.value = dic.id;
        op.text = dic.text;
        op.setAttribute('selected','selected');
        document.getElementById(dic.popbackid).appendChild(op);

    }
    function popUp(url) {
        var popupPage = window.open(url, url, "status=1, height:500, 600, toolbar=0, resizeable=0");
    }
</script>
add_view.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>正在关闭</title>
</head>
<body>
    <script>
        (function () {
            var dic = {{ json_result|safe }};
            opener.popupCallback(dic);
            window.close();
        })()

    </script>
</body>
</html>
popup_response.html
 def add_view(self, request, *args, **kwargs):

        model_form_class = self.get_model_form_class()
        _popbackid = request.GET.get('_popbackid')

        if request.method == "GET":
            form = model_form_class()
            from django.forms import ModelChoiceField
            new_choice = []
            for bfield in form:
                temp = {"is_popup":False,"item":bfield}
                if isinstance(bfield.field,ModelChoiceField):
                    #获取类名
                    related_class_name = bfield.field.queryset.model
                    app_model_name = related_class_name._meta.app_label,related_class_name._meta.model_name
                    print(app_model_name)
                    base_url = reverse("stark:%s_%s_add"%app_model_name)
                    popurl = "%s?_popbackid=%s"%(base_url,bfield.auto_id)
                    temp["popup_url"] = popurl
                    temp["is_popup"] = True
                new_choice.append(temp)

            return render(request, "stark/add_view.html", {"form": new_choice})
        else:
            form = model_form_class(request.POST)
            if form.is_valid():
                form_obj = form.save()
                if _popbackid:
                    # 是popup请求
                    # render一个页面,写自执行函数
                    result = {'id':form_obj.pk, 'text':str(form_obj),'popbackid':_popbackid }
                    return render(request,'stark/popup_response.html',{'json_result':json.dumps(result,ensure_ascii=False)})
                else:
                    return redirect(self.get_list_url())
            else:
                return render(request, "stark/add_view.html", {"form": form})
v1.py

阶段三:  编辑和增加生成的页面都用到popup 代码需要重写一次,so引入 templatetags

from django.template import Library
from django.forms import ModelChoiceField
from django.shortcuts import reverse

register = Library()



@register.inclusion_tag('stark/form.html')
def form(model_form_obj):

    new_choice = []
    for bfield in model_form_obj:
        temp = {"is_popup": False, "item": bfield}
        if isinstance(bfield.field, ModelChoiceField):
            # 获取类名
            related_class_name = bfield.field.queryset.model
            app_model_name = related_class_name._meta.app_label, related_class_name._meta.model_name
            print(app_model_name)
            base_url = reverse("stark:%s_%s_add" % app_model_name)
            popurl = "%s?_popbackid=%s" % (base_url, bfield.auto_id)
            temp["popup_url"] = popurl
            temp["is_popup"] = True
        new_choice.append(temp)
    
    return {"form": new_choice}
templatetags/change.form.py
{% load staticfiles %}
{% load change_form %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static "stark/bootstrap/css/bootstrap.css" %}" />
    <link rel="stylesheet" href="{% static "stark/css/stark-form.css" %}" />
</head>
<body>

    <div class="container" style=" 800px;height: 500px">
        <h1 class="text-center">增加页面</h1>
        {% form form %}
    </div>
</body>
</html>
add_view.html
{% load staticfiles %}
{% load change_form %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static "stark/bootstrap/css/bootstrap.css" %}" />
    <link rel="stylesheet" href="{% static "stark/css/stark-form.css" %}" />
</head>
<body>
{#    <h1>修改页面</h1>#}
{#        <form method="post" novalidate>#}
{#            {% csrf_token %}#}
{#            {{ form.as_p }}#}
{#            <input type="submit" value="提交">#}
{#        </form>#}

    <div class="container" style=" 800px;height: 500px">
        <h1 class="text-center">编辑页面</h1>
        {% form form %}
    </div>



    </body>
</html>
change_view.html
    def add_view(self, request, *args, **kwargs):

        model_form_class = self.get_model_form_class()
        _popbackid = request.GET.get('_popbackid')

        if request.method == "GET":
            form = model_form_class()

            return render(request, "stark/add_view.html", {"form": form})
        else:
            form = model_form_class(request.POST)
            if form.is_valid():
                form_obj = form.save()
                if _popbackid:
                    # 是popup请求
                    # render一个页面,写自执行函数
                    result = {'id':form_obj.pk, 'text':str(form_obj),'popbackid':_popbackid }
                    return render(request,'stark/popup_response.html',{'json_result':json.dumps(result,ensure_ascii=False)})
                else:
                    return redirect(self.get_list_url())
            else:
                return render(request, "stark/add_view.html", {"form": form})
def add_view()

12. 其它列可编辑

子类
#8. 其它列可编辑
    # def get_list_display(self):
    #     data = []
    #     if self.list_display:
    #         data.extend(self.list_display)
    #         data.append(v1.StarkConfig.delete)
    #         data.insert(0, v1.StarkConfig.checkbox)
    #     return data
    edit_link = ["title"]


class StarkConfig(object):
    edit_link = ["title"]

    edit_link = []
    def get_edit_link(self):
        result = []
        if self.edit_link:
            result.extend(self.edit_link)
        return result

class ChangeList(object):
    self.edit_link = config.get_edit_link()

    def body_list(self):
        # 处理表中的数据
        # [ UserInfoObj,UserInfoObj,UserInfoObj,UserInfoObj,]
        # [ UserInfo(id=1,name='alex',age=18),UserInfo(id=2,name='alex2',age=181),]
        data_list = self.data_list
        new_data_list = []
        for row in data_list:
            # row是 UserInfo(id=2,name='alex2',age=181)
            # row.id,row.name,row.age
            temp = []
            for field_name in self.list_display:
                if isinstance(field_name,str):
                    val = getattr(row,field_name) # # 2 alex2
                    # 判断是否在编辑列表中
                    if field_name in self.edit_link:
                        val = self.edit_link_url(row.pk,val)
                else:
                    val = field_name(self.config,row)
                temp.append(val)
            new_data_list.append(temp)

        return new_data_list    


    # 其它列的作为编辑功能的url
    def edit_link_url(self,pk,text):
        query_str = self.request.GET.urlencode()  # page=2&nid=1
        params = QueryDict(mutable=True)
        params[self.config._query_param_key] = query_str

        return mark_safe('<a href="%s?%s">%s</a>' % (self.config.get_change_url(pk), params.urlencode(),text))
View Code

 

 

  

 

 

整个流程 

1. Django项目启动 自动加载文件 制作启动文件
    
    1. 注册strak 在apps.py 类里面增加如下 

        def ready(self):
            from django.utils.module_loading import autodiscover_modules
            autodiscover_modules("stark")

    2. 在已经注册的app中创建stark.py文件 加载


2. 在stark中模仿AdminSite ModelAdmin类写代码 注册自己的类

    class StarkConfig(object):

        def __init__(self,model_class,site):
            self.model_class = model_class
            self.site = site


    class StarkSite(object):

        def __init__(self):
            self._registey = {}

        def register(self,model_class,stark_config_class=None):
            if not stark_config_class:
                stark_config_class = StarkConfig

            self._registey[model_class] = stark_config_class(model_class,self)

    site = StarkSite()


3. 将注册的类自动生成url

    - urls.py
        from stark.service import v1

        urlpatterns = [
            url(r'^stark/', v1.site.urls),
        ]

    - 为每个类生成4个url v1.py 
        
        class StarkConfig(object):

            def __init__(self,model_class,site):
                self.model_class = model_class
                self.site = site

            def get_urls(self):
                app_model_name = (self.model_class._meta.app_label,self.model_class._meta.model_name,)
                url_patterns = [
                    url(r'^$',self.changelist_view,name="%s_%s_changlist" %app_model_name),
                    url(r'^add/$',self.add_view,name="%s_%s_add" %app_model_name),
                    url(r'^(d+)/delete/$',self.delete_view,name="%s_%s_delete" %app_model_name),
                    url(r'^(d+)/change/$',self.change_view,name="%s_%s_chang" %app_model_name),
                ]
                return url_patterns

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

            def changelist_view(self,request,*args,**kwargs):
                return HttpResponse('列表')

            def add_view(self,request,*args,**kwargs):
                return HttpResponse('添加')

            def delete_view(self,request,nid,*args,**kwargs):
                return HttpResponse('删除')

            def change_view(self,request,nid,*args,**kwargs):
                return HttpResponse('修改')


        class StarkSite(object):

            def __init__(self):
                self._registey = {}

            def register(self,model_class,stark_config_class=None):
                if not stark_config_class:
                    stark_config_class = StarkConfig

                self._registey[model_class] = stark_config_class(model_class,self)

            def get_urls(self):
                url_pattern = []

                for model_class,stark_config_obj in self._registry.items():
                   
                    app_name = model_class._meta.app_label
                    model_name = model_class._meta.model_name

                    curd_url = url(r'^%s/%s/' %(app_name,model_name,) , (stark_config_obj.urls,None,None))
                    url_pattern.append(curd_url)

                return url_pattern


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


        site = StarkSite()

4. 列表页面展示

- v1.py
    def changelist_view(self,request,*args,**kwargs):
    # 处理表头

    head_list = []
    for field_name in self.list_display:
        if isinstance(field_name,str):
            # 根据类和字段名称,获取字段对象的verbose_name
            verbose_name = self.model_class._meta.get_field(field_name).verbose_name
        else:
            verbose_name = field_name(self,is_header=True)
        head_list.append(verbose_name)

    # 处理表中的数据
    # [ UserInfoObj,UserInfoObj,UserInfoObj,UserInfoObj,]
    # [ UserInfo(id=1,name='alex',age=18),UserInfo(id=2,name='alex2',age=181),]
    data_list = self.model_class.objects.all()
    new_data_list = []
    for row in data_list:
        # row是 UserInfo(id=2,name='alex2',age=181)
        # row.id,row.name,row.age
        temp = []
        for field_name in self.list_display:
            if isinstance(field_name,str):
                val = getattr(row,field_name) # # 2 alex2
            else:
                val = field_name(self,row)
            temp.append(val)
        new_data_list.append(temp)

    return render(request,'stark/changelist.html',{'data_list':new_data_list,'head_list':head_list})

- shark.py
    class UserInfoConfig(v1.StarkConfig):

    def checkbox(self,obj=None,is_header=False):
        if is_header:
            return '选择'
        return mark_safe('<input type="checkbox" name="pk" value="%s" />' %(obj.id,))
    def edit(self,obj=None,is_header=False):
        if is_header:
            return '编辑'
        return mark_safe('<a href="/edit/%s">编辑</a>' %(obj.id,))

    list_display = [checkbox,'id','name',edit]



4. 显示增加按钮

    - 先判断是否显示,再通过反向解析生成增加链接
    - 后端
        # 是否显示增加按钮
        show_add_btn = True
        def get_show_btn(self):
            return self.show_add_btn

        return render(request, 'stark/changelist.html', {'data_list': new_data_list, 'head_list': head_list,"add_url":self.get_add_url(),"show_add_btn":self.get_show_btn()})

    - 前端
        {% if show_add_btn %}
            <a class="btn btn-primary" href="{{ add_url }}">增加</a>
        {% endif %}


5. 增加内容页面

    1. 通过ModelForm创建公共类 显示和提交

        - 后端

            def add_view(self, request, *args, **kwargs):

                class AddTable(ModelForm):
                    class Meta:
                        model = self.model_class
                        fields = "__all__"

                if request.method == "GET":
                    form = AddTable()
                    return render(request,"stark/add_view.html",{"form":form})
                else:
                    form = AddTable(request.POST)
                    if form.is_valid():
                        form.save()
                        return redirect(self.get_list_url())
                    else:
                        return render(request, "stark/add_view.html", {"form": form})

        - 前端
            <form method="post" novalidate>
                {% csrf_token %}
                {{ form.as_p }}
                <input type="submit" value="提交">
            </form>

    2. 升级 在子类自定义ModelForm类 子类之后可以自定义类

        - v1.py
            model_form_class = None
                def get_model_form_class(self):
                    if self.model_form_class:
                        return self.model_form_class
                    else:
                        #方式一:
                        # class AddTable(ModelForm):
                        #     class Meta:
                        #         model = self.model_class
                        #         fields = "__all__"
                        # return AddTable
                        #方式二:
                        meta = type("Meta",(object,),{"model":self.model_class,"fields":"__all__"})
                        AddTable = type("AddTable",(ModelForm,),{"Meta":meta})
                        return AddTable


            def add_view(self, request, *args, **kwargs):
                model_form_class = self.get_model_form_class()
                if request.method == "GET":
                    form = model_form_class()
                    return render(request,"stark/add_view.html",{"form":form})
                else:
                    form = model_form_class(request.POST)
                    if form.is_valid():
                        form.save()
                        return redirect(self.get_list_url())
                    else:
                        return render(request, "stark/add_view.html", {"form": form})
        - stark.py

            class UserInfoModelForm(ModelForm):
                class Meta:
                    model = models.UserInfo
                    fields = ["name","password"]
                    error_messages = {
                        "name":{
                            'required':'用户名不能为空'
                        }
                    }
            class UserInfoConfig(v1.StarkConfig):
                model_form_class = UserInfoModelForm


6. 修改 和 删除
    def change_view(self, request, nid, *args, **kwargs):

        obj = self.model_class.objects.filter(pk=nid).first()
        if not obj:
            return redirect(self.get_list_url())
        model_form_class = self.get_model_form_class()
        if request.method == "GET":
            form = model_form_class(instance=obj)
            return render(request,"stark/change_view.html",{"form":form})
        else:
            form = model_form_class(instance=obj,data=request.POST)
            if form.is_valid:
                form.save()
                return redirect(self.get_list_url())
            return render(request,"stark/change_view.html",{"form":form})

    def delete_view(self, request, nid, *args, **kwargs):
        self.model_class.objects.filter(pk=nid).delete()
        return redirect(self.get_list_url())
View Code
原文地址:https://www.cnblogs.com/golangav/p/8043656.html