• stark


    一、filter

    效果图

    知识点

    1.配置得显示Filter,不配置就不显示了
    list_filter = ['title','publish', 'authors']

    2.前端显示
    后端返回 字典
    eg:{"publish":["<a href=''>全部</a>","<a href=''>南京出版社</a>","<a href=''>上海出版社</a>"]
    "authors":["<a href=''>全部</a>","<a href=''>yuan</a>","<a href=''>egon</a>"]
    }

    {% if showlist.config.list_filter %}
    <h4>Filter</h4>
    {% for filter_field, linktags in showlist.get_filter_linktags.items %}
    <div class="well">
    <p>{{ filter_field.upper }}</p>
    {% for link in linktags %}
    <p>{{ link|safe }}</p>
    {% endfor %}

    </div>
    {% endfor %}
    {% endif %}

    3.get_filter_linktags 返回 字典
    知识:
    1.根据字段 str 取到模型得字段对象
    filter_field_obj = self.config.model._meta.get_field(filter_field)
    model_name = self.config.model._meta.model_name # 模型名 book
    app_label = self.config.model._meta.app_label # app名 app01

    2.一对多,多对多,
    就是 ForeignKey ManyToManyField 得对象
    app01.Book.publish
    <class 'django.db.models.fields.related.ForeignKey'>
    app01.Book.authors
    <class 'django.db.models.fields.related.ManyToManyField'>

    3.根据一对多,多对多得对象 找关联得模型表,数据
    print("rel...", filter_field_obj.rel.to.objects.all())
    rel... <QuerySet [<Publish: 南京出版社>, <Publish: 上海出版社>, <Publish: 河北出版社>]>
    rel... <QuerySet [<Author: yuan>, <Author: egon>, <Author: alex>]>

    4.取数据,普通字段,和关联字段分开取
    if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
    data_list = filter_field_obj.rel.to.objects.all() # 关联对象 适用 一对多,多对多
    else: # 普通字段
    data_list = self.config.model.objects.all().values('pk', filter_field)

    5.处理全部标签时
    注意:url 上面已经有了该field, 全部,就取消该field, del params[filter_field]
    url 上面没有,那就没有
    temp = []
    if params.get(filter_field):
    del params[filter_field]
    temp.append("<a href='?%s'>全部</a>" % (params.urlencode()))
    else:
    temp.append("<a href='#' class='active'>全部</a>")

    6.处理数据标签
    注意:分开处理关联字段和普通字段
    params = copy.deepcopy(self.request.GET)
    为url加一个params
    params[filter_field] = pk
    params[filter_field] = text

    每一次取数据都要保留 正在访问得 url 并加上正在访问得field!

    _url = params.urlencode()
    link_tag = "<a href='?%s'>%s</a>" % (_url, text)

    正在点击得,得加上样式 active
    if cid == str(pk) or cid == text:
    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
    else:
    link_tag = "<a href='?%s'>%s</a>" % (_url, text)
            # 处理数据标签
            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
    
                _url = params.urlencode() # 序列化后得结构
    
                if cid == str(pk) or cid == text:
                    link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
                else:
                    link_tag = "<a href='?%s'>%s</a>" % (_url, text)
    
                temp.append(link_tag)
    
            link_dic[filter_field] = temp
        def get_filter_linktags(self):
            print('list_filter:',self.config.list_filter) # ['title', 'publish', 'authors']
    
            link_dic = {}
            import copy
    
            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)
                print(filter_field_obj)
                print(type(filter_field_obj))
                """
                app01.Book.title
                <class 'django.db.models.fields.CharField'>
                app01.Book.publish
                <class 'django.db.models.fields.related.ForeignKey'>
                app01.Book.authors
                <class 'django.db.models.fields.related.ManyToManyField'>
                """
    
                from django.db.models.fields.related import ForeignKey
                from django.db.models.fields.related import ManyToManyField
    
                # print("rel...", filter_field_obj.rel.to.objects.all())
                # rel... <QuerySet [<Publish: 南京出版社>, <Publish: 上海出版社>, <Publish: 河北出版社>]>
                # rel... <QuerySet [<Author: yuan>, <Author: egon>, <Author: alex>]>
    
                if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                    data_list = filter_field_obj.rel.to.objects.all()  # 关联对象 适用 一对多,多对多
                else: # 普通字段
                    data_list = self.config.model.objects.all().values('pk', filter_field)
    
                # 处理全部标签
                temp = []
                if params.get(filter_field):
                    del params[filter_field]
                    temp.append("<a href='?%s'>全部</a>" % (params.urlencode()))
                else:
                    temp.append("<a href='#' class='active'>全部</a>")
    
                # 处理数据标签
                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
    
                    _url = params.urlencode() # 序列化后得结构
    
                    if cid == str(pk) or cid == text:
                        link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
                    else:
                        link_tag = "<a href='?%s'>%s</a>" % (_url, text)
    
                    temp.append(link_tag)
    
                link_dic[filter_field] = temp
    
            return link_dic


    4.Q查询 and
    def list_view(self, request):
    ...
    ...
    # 获取filter得Q对象
    filter_condition = self.get_filter_condition(request)

    # 筛选当前表得所有数据
    data_list = self.model.objects.all().filter(search_connection).filter(filter_condition)
    ...
    ...

    # Q对象
    def get_filter_condition(self, request):
    filter_condition = Q() # 默认是 and 不是 or, 根据str,查找val
    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

    补充:
    Q查询根据字段
    bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
    Q查询根据str
    filter_condition = Q()
    filter_consition.connector = "or" # 如果不写默认是 and
    filter_condition.children.append(("title","yuan"))
    filter_condition.children.append(("date","2018-12-12"))

    Book.object.filter(filter_condition)

    app01/stark.py

    # -*- coding:utf-8 -*-
    from stark.service import stark
    from .models import *
    from django.forms import ModelForm
    
    class BookModelForm(ModelForm):
        class Meta:
            model = Book
            fields = "__all__"
            labels = {
                "title": '书籍名称',
                "price": '价格',
                'publishDate': '出版日期'
            }
    
    from django.shortcuts import HttpResponse
    class BookConfig(stark.ModelStark):
    
        list_display = ['title', 'price','publishDate']
        list_display_links = ['title']
        modelform_class = BookModelForm
        search_fields = ['title', 'price']
    
        def patch_init(self, request, queryset):
            # print("queryset",queryset)
            queryset.update(price=123)
    
            return HttpResponse('批量初始化OK')
    
        patch_init.short_description = "批量初始化"
        actions = [patch_init]
    
        list_filter = ['title','publish', 'authors']
    
    
    stark.site.register(Book, BookConfig)
    stark.site.register(Publish)
    stark.site.register(Author)
    stark.site.register(AuthorDetail)
    stark.py

    stark/service/stark.py

    from django.conf.urls import url
    from django.shortcuts import HttpResponse, reverse, redirect, render
    from django.utils.safestring import mark_safe
    from django.urls import reverse
    from django.forms import ModelForm
    from stark.utils.page import Pagination
    from django.db.models import Q
    
    class ShowList(object):
        def __init__(self, config, data_list, request):
            self.config = config
            self.data_list = data_list
            self.request = request
    
            # 分页
            data_count = self.data_list.count()
            current_page = self.request.GET.get('page',1)
            base_path = self.request.path
    
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=3, pager_count=11)
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
    
            self.actions = self.config.new_actions()
    
    
        def get_filter_linktags(self):
            print('list_filter:',self.config.list_filter) # ['title', 'publish', 'authors']
    
            link_dic = {}
            import copy
    
            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)
                print(filter_field_obj)
                print(type(filter_field_obj))
                """
                app01.Book.title
                <class 'django.db.models.fields.CharField'>
                app01.Book.publish
                <class 'django.db.models.fields.related.ForeignKey'>
                app01.Book.authors
                <class 'django.db.models.fields.related.ManyToManyField'>
                """
    
                from django.db.models.fields.related import ForeignKey
                from django.db.models.fields.related import ManyToManyField
    
                # print("rel...", filter_field_obj.rel.to.objects.all())
                # rel... <QuerySet [<Publish: 南京出版社>, <Publish: 上海出版社>, <Publish: 河北出版社>, <Publish: 3>]>
                # rel... <QuerySet [<Author: yuan>, <Author: egon>, <Author: alex>]>
    
                if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                    data_list = filter_field_obj.rel.to.objects.all()  # 关联对象 适用 一对多,多对多
                else: # 普通字段
                    data_list = self.config.model.objects.all().values('pk', filter_field)
    
                # 处理全部标签
                temp = []
                if params.get(filter_field):
                    del params[filter_field]
                    temp.append("<a href='?%s'>全部</a>" % (params.urlencode()))
                else:
                    temp.append("<a href='#' class='active'>全部</a>")
    
                # 处理数据标签
                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
    
                    _url = params.urlencode() # 序列化后得结构
    
                    if cid == str(pk) or cid == text:
                        link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
                    else:
                        link_tag = "<a href='?%s'>%s</a>" % (_url, text)
    
                    temp.append(link_tag)
    
                link_dic[filter_field] = temp
    
            return link_dic
    
        def get_action_list(self):
            temp = []
            for action in self.actions:
                temp.append({
                    "name": action.__name__,
                    "desc":action.short_description
                })
    
            return temp
        
    
        def get_header(self):
            # 构建表头
            header_list = []
            # header_list = ['选择','pk',...'操作','操作']
            for field in self.config .new_list_play():
                if callable(field):
                    val = field(self.config, header=True)
                else:
                    if field == "__str__":
                        val = self.config .model._meta.model_name.upper()
                    else:  # 根据str 拿字段对象 取中文
                        val = self.config .model._meta.get_field(field).verbose_name
    
                header_list.append(val)
    
            return header_list
    
        def get_body(self):
            # 构建表单
            new_data_list = []
            for data in self.page_data:
                temp = []
                for field in self.config.new_list_play():  # ['title','price'] 字符串找对象得属性 反射
                    # print('field:', field)
                    if callable(field):
                        val = field(self.config, data)
                    else:
                        val = getattr(data, field)
    
                        if field in self.config.list_display_links:
                            _url = self.config.get_change_url(data)
                            val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
    
                    temp.append(val)
    
                new_data_list.append(temp)  # [['yuan', 12], ['alex', 18], ['egon', 22]]
    
            return new_data_list
    
    
    class ModelStark(object):
        list_display = ["__str__"]
        list_display_links = []
        modelform_class = []
        search_fields = []
        actions = []
        list_filter = []
    
        def __init__(self, model, site):
            self.model = model
            self.site = site
    
        def patch_delete(self, request, queryset):
            queryset.delete()
        patch_delete.short_description = "批量删除"
    
    
        def edit(self, obj=None, header=False):
            if header:
                return "操作"
    
            _url = self.get_change_url(obj)
            return mark_safe("<a href='%s'>编辑</a>" % _url)
    
        def deletes(self, obj=None, header=False):
            if header:
                return '操作'
    
            _url = self.get_delete_url(obj)
            return mark_safe("<a href='%s'>删除</a>" % _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='%s'>" % obj.pk)
    
        def get_modelform_class(self):
            if not self.modelform_class:
                class ModelFormDemo(ModelForm):
                    class Meta:
                        model = self.model
                        fields = "__all__"
                return ModelFormDemo
            else:
                return self.modelform_class
    
        def add_view(self, request):
            ModelFormDemo = self.get_modelform_class()
            form = ModelFormDemo()
    
            if request.method == 'POST':
                form = ModelFormDemo(request.POST)
                if form.is_valid():
                    form.save()
                    return redirect(self.get_list_url())
    
            return render(request, 'add_view.html', locals())
    
        def delete_view(self, request, delete_id):
            url = self.get_list_url()
    
            if request.method == 'POST':
                self.model.objects.filter(pk=delete_id).delete()
                return redirect(url)
    
            return render(request, 'delete_view.html', locals())
    
        def change_view(self, request, change_id):
            ModelFormDemo = self.get_modelform_class()
            edit_obj = self.model.objects.filter(pk=change_id).first()
            form = ModelFormDemo(instance=edit_obj)
    
            if request.method == "POST":
                form = ModelFormDemo(request.POST, instance=edit_obj)
                if form.is_valid():
                    form.save()
                    return redirect(self.get_list_url())
    
            return render(request,'change_view.html', locals())
    
        def new_list_play(self):
            temp = []
            temp.append(ModelStark.checkbox)
            temp.extend(self.list_display)
            temp.append(ModelStark.edit)
            temp.append(ModelStark.deletes)
    
            return temp
    
        def new_actions(self):
            temp = []
            temp.append(ModelStark.patch_delete)
            temp.extend(self.actions)
    
            return temp
    
        def get_change_url(self, obj):
            model_name = self.model._meta.model_name
            app_lable = self.model._meta.app_label
    
            _url = reverse("%s_%s_change" % (app_lable, model_name), args=(obj.pk,))
    
            return _url
    
        def get_delete_url(self, obj):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,))
    
            return _url
    
        def get_add_url(self):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_add" % (app_label, model_name))
    
            return _url
    
        def get_list_url(self):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_list" % (app_label, model_name))
    
            return _url
    
        def get_search_condition(self, request):
            key_words = request.GET.get('q', "")
            self.key_words = key_words
            search_connection = Q()
            if key_words:
                search_connection.connector = "or"
                for search_field in self.search_fields:
                    search_connection.children.append((search_field+"__contains", key_words))
    
            return search_connection
    
        def get_filter_condition(self, request):
            filter_condition = Q()   # 默认是 and 不是 or
            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":
                print("request.POST:",request.POST)
                # 'action': ['patch_init'], 'selected_pk': ['1', '2']
                action = request.POST.get('action')
                selected_pk = request.POST.getlist('selected_pk')
                action_func = getattr(self, action) # 反射
                queryset = self.model.objects.filter(pk__in=selected_pk)  # 秒!!!
                ret = action_func(request, queryset)
                # return ret
    
            # 获取searchd得Q对象
            search_connection = self.get_search_condition(request)
    
            # 获取filter得Q对象
            filter_condition = self.get_filter_condition(request)
    
            # 筛选当前表得所有数据
            data_list = self.model.objects.all().filter(search_connection).filter(filter_condition)
            
            # 展示数据
            showlist = ShowList(self, data_list, request)
    
            # 构建一个查看url
            add_url = self.get_add_url()
            return render(request, 'list_view.html',locals())
    
        def get_urls2(self):
            temp = []
    
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            temp.append(url(r'add/', self.add_view, name="%s_%s_add" % (app_label, model_name)))
            temp.append(url(r'(d+)/delete/', self.delete_view, name="%s_%s_delete" % (app_label, model_name)))
            temp.append(url(r'(d+)/change/', self.change_view, name="%s_%s_change" % (app_label, model_name)))
            temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name)))
    
            return temp
    
        @property
        def urls2(self):
    
            return self.get_urls2(), None, None
    
    
    class StarkSite(object):
        def __init__(self):
            self._registry = {}
    
        def register(self, model, stark_class=None):
            if not stark_class:
                stark_class = ModelStark
    
            self._registry[model] = stark_class(model,self)
    
    
        def get_urls(self):
            temp = []
            
            # 模型表,配置类对象
            for model, stark_class_obj in self._registry.items():
                model_name = model._meta.model_name
                app_label = model._meta.app_label
    
                # 分发增删改查
                temp.append(url(r'%s/%s/'%(app_label,model_name), stark_class_obj.urls2))
    
            return temp
    
        @property
        def urls(self):
    
            return self.get_urls(), None, None
    
    
    site = StarkSite()
    stark.py

    list_view.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
        <script src="/static/js/jquery-1.12.4.min.js"></script>
        <style type="text/css">
            .filter a{text-decoration: none; color: grey}
            .active{ color: red!important;}
        </style>
    </head>
    <body>
    
    <h4>数据列表</h4>
    
    <div class="container">
        <div class="row">
            <div class="col-md-9">
                <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
    
                {% if showlist.config.search_fields %}
                    <form action="" class="pull-right">
                        <input type="text" name="q" value="{{ showlist.config.key_words }}"><button>submit</button>
                    </form>
                {% endif %}
    
                <form action="" method="post">
                    {% csrf_token %}
                    <select name="action" id="" style=" 200px; padding: 5px 8px; display: inline-block; ">
                        <option value="">------------</option>
                        {% for item in showlist.get_action_list %}
                            <option value="{{ item.name }}">{{ item.desc }}</option>
                        {% endfor %}
    
                    </select><button type="submit" class="btn btn-info">GO</button>
    
                    <table class="table table-bordered table-striped">
                        <thead>
                        <tr>
                            {% for item in showlist.get_header %}
                                <th>{{ item }}</th>
                            {% endfor %}
    
                        </tr>
    
                        </thead>
                        <tbody>
                        {% for data in showlist.get_body %}
                            <tr>
                                {% for item in data %}
                                    <td>{{ item }}</td>
                                {% endfor %}
    
                            </tr>
                        {% endfor %}
    
                        </tbody>
                    </table>
    
                    <nav>
                        <ul class="pagination">
                            {{ showlist.pagination.page_html|safe }}
                        </ul>
                    </nav>
    
                </form>
    
    
            </div>
    
            <div class="col-md-3">
                {% if showlist.config.list_filter %}
                    <h4>Filter</h4>
                    {% for filter_field, linktags in showlist.get_filter_linktags.items %}
                        <div class="well">
                            <p>{{ filter_field.upper }}</p>
                            {% for link in linktags %}
                                <p>{{ link|safe }}</p>
                            {% endfor %}
    
                        </div>
                    {% endfor %}
                {% endif %}
    
            </div>
        </div>
    </div>
    
    <script type="text/javascript">
        $('#choice').click(function () {
            if($(this).prop('checked')){
                $('.choice_item').prop('checked',true)
            }else{
                $('.choice_item').prop('checked',false)
            }
        })
    
    
    </script>
    
    </body>
    </html>
    list_view.html

    二、pop

    效果图

    知识点

    pop功能:
    1.在一对多和多对多字段后渲染 +
    2.+对应的跳转路径
    3.保存添加记录同时,将原页面的对应的下拉菜单中添加该记录

    --------------------------
    知识点:
    1.在一对多和多对多字段后渲染+
    后台需要先判断 是否是 一对多 多对多字段
    modelform, 遍历
    for bfield in form:
    print(bfield.field) # 是每个form字段对象
    所以:判断是否是一对多,多对多字段
    if isinstance(bfield.field, ModelChoiceField):
    bfield.is_pop = True # 为特殊字段加上特有属性,方便前端判断。

    注意:ModelMultipleChoiceField(多对多) 继承 ModelChoiceField(一对多)
    ModelChoiceField 继承 ChoiceField
        for bfield in form:
            print(type(bfield))  # 字段类型
                # <class 'django.forms.boundfield.BoundField'>
    
            print('name', bfield.name)  # 字段名字符串 publish authors
    
            from django.forms.boundfield import BoundField
            print(bfield.field)  # 字段对象
            # <django.forms.fields.CharField object at 0x0000014BD355EBA8>
            # <django.forms.models.ModelChoiceField object at 0x0000014BD355ECF8>
            # <django.forms.models.ModelMultipleChoiceField object at 0x0000014BD355ED68>
    
            from django.forms.models import ModelChoiceField
                if isinstance(bfield.field, ModelChoiceField):
                    # 给一对多,多对多字段,对象加个属性is_pop;前端就可以判断在哪个位置加+
                    bfield.is_pop = True
    
        注意: ModelMultipleChoiceField 继承 ModelChoiceField
             所以:只需要判断 isinstance(bfield.field, ModelChoiceField)

    2.+对应的跳转路径
    form表单得一对多,多对多得字段对象
    bfield.field.queryset.model # 相关联得模型!!<class 'app01.models.Publish'>
    #(模型表得对象去找 filter_field_obj.rel.to.objects.all(),到to是模型。)

    根据queryset找model queryset.model
    根据model找queryset model.objects.all()

    related_model_name = bfield.field.queryset.model._meta.model_name # publish
    related_app_label = bfield.field.queryset.model._meta.app_label # app01

    反向解析url
    _url = reverse("%s_%s_add" % (related_app_label, related_model_name))

    # 为bfield添加自己特有的url,
    # ?后面是为了,区分是top,还是正常页面打开/add/,方便之后关闭,以及赋值。
    bfield.url = _url + "?pop_res_id=id_%s" % bfield.name

        if isinstance(bfield.field, ModelChoiceField):
            bfield.is_pop = True
    
            print('---',bfield.field.queryset.model)
            # <class 'app01.models.Publish'>
            # <class 'app01.models.Author'>
            related_model_name = bfield.field.queryset.model._meta.model_name
            related_app_label = bfield.field.queryset.model._meta.app_label
            _url = reverse("%s_%s_add" % (related_app_label, related_model_name))
            bfield.url = _url + "?pop_res_id=id_%s" % bfield.name
    
    
    3.关闭弹出得top页面
    top弹出,关闭页面,回到到原页面;
    正常添加,跳转到list页面;

    返回 res = {"pk":obj.pk, 'text':str(obj), "pop_res_id": pop_res_id}
    pop.html,方便关闭pop页面

    pop.html:
    关闭以及将接收得数据传到原页面上!
    window.opener.pop_response("{{ res.pk}}","{{ res.text }}","{{ res.pop_res_id }}");
    window.close()

        # 两种情况
        pop_res_id = request.GET.get('pop_res_id')
        if pop_res_id:
            res = {"pk":obj.pk, 'text':str(obj), "pop_res_id": pop_res_id}
            return render(request,'pop.html',{"res":res})
        else:
            return redirect(self.get_list_url())
    
        <script type="text/javascript">
            window.opener.pop_response("{{ res.pk}}","{{ res.text }}","{{ res.pop_res_id }}");
            window.close()
        </script>

    4.原页面接收数据,并显示刚添加得数据(window.opener
    拿到 id, text, pop_res_id
    动态创建 option append到对应得下拉框中,并选中;
    var $option = $("<option>");
    $option.html(text);
    $option.val(pk);
    $option.attr('selected','selected');

    $('#'+pop_res_id).append($option)

        pop.html
            window.opener.pop_response("{{ res.pk}}","{{ res.text }}","{{ res.pop_res_id }}");
            window.close()
    
         add_view.html
    <script type="text/javascript"> function pop_response(pk, text,pop_res_id) { console.log(pk); console.log(text); console.log(pop_res_id); // optiond得文本值 和value var $option = $("<option>"); //<option></option> $option.html(text); $option.val(pk); $option.attr('selected','selected'); $('#'+pop_res_id).append($option) } </script>
    
    
        前端展示:定位,(父相子绝)
         <div style="position: relative">
            {% if field.is_pop %}
                <a onclick="pop('{{ field.url }}')"><span style="font-size: 23px;position: absolute; right: -23px; top: 25px;">+</span></a>
            {% endif %}
         </div>
    
    def add_view(self, request): ModelFormDemo = self.get_modelform_class() form = ModelFormDemo() for bfield in form: print('i::', type(bfield)) # 字段类型 # print('i::', bfield.field) # 字段对象 # print('name', bfield.name) # 字段名字符串 publish authors # <class 'django.forms.boundfield.BoundField'> from django.forms.boundfield import BoundField print(bfield.field) from django.forms.models import ModelChoiceField from django.forms.models import ModelMultipleChoiceField # <django.forms.fields.CharField object at 0x0000014BD355EBA8> # <django.forms.models.ModelChoiceField object at 0x0000014BD355ECF8> # <django.forms.models.ModelMultipleChoiceField object at 0x0000014BD355ED68> from django.forms.models import ModelChoiceField if isinstance(bfield.field, ModelChoiceField): bfield.is_pop = True print('---',bfield.field.queryset.model) # <class 'app01.models.Publish'> # <class 'app01.models.Author'> related_model_name = bfield.field.queryset.model._meta.model_name related_app_label = bfield.field.queryset.model._meta.app_label _url = reverse("%s_%s_add" % (related_app_label, related_model_name)) bfield.url = _url + "?pop_res_id=id_%s" % bfield.name if request.method == 'POST': form = ModelFormDemo(request.POST) if form.is_valid(): obj = form.save() # 两种情况 pop_res_id = request.GET.get('pop_res_id') if pop_res_id: res = {"pk":obj.pk, 'text':str(obj), "pop_res_id": pop_res_id} return render(request,'pop.html',{"res":res}) else: return redirect(self.get_list_url()) return render(request, 'add_view.html', locals())

    补充:

    ChoiceFiled
    ModelChoiceFiled(ChoiceFiled) ---- select(单选) --- ForeignKey
    MultiModelChoiceFiled (ModelChoiceFiled)----select(多选) --- ManyToManyField

    Book模型,form表单,modelform;
    modelform帮我们转成了form表单;

    bootstrap页面自适应: col-xs-8

    class Book(model.Model):
        title = models.CharField(max_length=32)
        price = models.IntegerField()
        publish=model.Foreignkey("Publish")
        authors=model.ManyToMany("Author")
    
    from django.forms import ModelForm
    class BookForm(ModelForm):
        class Meta:
            model=Book
            fields="__all__"
    
    from django import forms
    class BookForm(forms.Form):
        title=forms.CharField(max_length=32)
        price=forms.IntegerField()
        publish = forms.ModelChoiceFiled("Publish")
        authors = forms.ModelMultipleChoiceField("Author")
    
    form=BookForm()

    stark/service/stark.py

    from django.conf.urls import url
    from django.shortcuts import HttpResponse, reverse, redirect, render
    from django.utils.safestring import mark_safe
    from django.urls import reverse
    from django.forms import ModelForm
    from stark.utils.page import Pagination
    from django.db.models import Q
    
    class ShowList(object):
        def __init__(self, config, data_list, request):
            self.config = config
            self.data_list = data_list
            self.request = request
    
            # 分页
            data_count = self.data_list.count()
            current_page = self.request.GET.get('page',1)
            base_path = self.request.path
    
            self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=3, pager_count=11)
            self.page_data = self.data_list[self.pagination.start:self.pagination.end]
    
            self.actions = self.config.new_actions()
    
    
        def get_filter_linktags(self):
            print('list_filter:',self.config.list_filter) # ['title', 'publish', 'authors']
    
            link_dic = {}
            import copy
    
            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)
                print(filter_field_obj)
                print(type(filter_field_obj))
                """
                app01.Book.title
                <class 'django.db.models.fields.CharField'>
                app01.Book.publish
                <class 'django.db.models.fields.related.ForeignKey'>
                app01.Book.authors
                <class 'django.db.models.fields.related.ManyToManyField'>
                """
    
                from django.db.models.fields.related import ForeignKey
                from django.db.models.fields.related import ManyToManyField
    
                # print("rel...", filter_field_obj.rel.to.objects.all())
                # rel... <QuerySet [<Publish: 南京出版社>, <Publish: 上海出版社>, <Publish: 河北出版社>, <Publish: 3>]>
                # rel... <QuerySet [<Author: yuan>, <Author: egon>, <Author: alex>]>
    
                if isinstance(filter_field_obj, ForeignKey) or isinstance(filter_field_obj, ManyToManyField):
                    data_list = filter_field_obj.rel.to.objects.all()  # 关联对象 适用 一对多,多对多
                else: # 普通字段
                    data_list = self.config.model.objects.all().values('pk', filter_field)
    
                # 处理全部标签
                temp = []
                if params.get(filter_field):
                    del params[filter_field]
                    temp.append("<a href='?%s'>全部</a>" % (params.urlencode()))
                else:
                    temp.append("<a href='#' class='active'>全部</a>")
    
                # 处理数据标签
                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
    
                    _url = params.urlencode() # 序列化后得结构
    
                    if cid == str(pk) or cid == text:
                        link_tag = "<a class='active' href='?%s'>%s</a>" % (_url, text)
                    else:
                        link_tag = "<a href='?%s'>%s</a>" % (_url, text)
    
                    temp.append(link_tag)
    
                link_dic[filter_field] = temp
    
            return link_dic
    
        def get_action_list(self):
            temp = []
            for action in self.actions:
                temp.append({
                    "name": action.__name__,
                    "desc":action.short_description
                })
    
            return temp
        
    
        def get_header(self):
            # 构建表头
            header_list = []
            # header_list = ['选择','pk',...'操作','操作']
            for field in self.config .new_list_play():
                if callable(field):
                    val = field(self.config, header=True)
                else:
                    if field == "__str__":
                        val = self.config .model._meta.model_name.upper()
                    else:  # 根据str 拿字段对象 取中文
                        val = self.config .model._meta.get_field(field).verbose_name
    
                header_list.append(val)
    
            return header_list
    
        def get_body(self):
            # 构建表单
            new_data_list = []
            for data in self.page_data:
                temp = []
                for field in self.config.new_list_play():  # ['title','price'] 字符串找对象得属性 反射
                    # print('field:', field)
                    if callable(field):
                        val = field(self.config, data)
                    else:
                        val = getattr(data, field)
    
                        if field in self.config.list_display_links:
                            _url = self.config.get_change_url(data)
                            val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
    
                    temp.append(val)
    
                new_data_list.append(temp)  # [['yuan', 12], ['alex', 18], ['egon', 22]]
    
            return new_data_list
    
    
    class ModelStark(object):
        list_display = ["__str__"]
        list_display_links = []
        modelform_class = []
        search_fields = []
        actions = []
        list_filter = []
    
        def __init__(self, model, site):
            self.model = model
            self.site = site
    
        def patch_delete(self, request, queryset):
            queryset.delete()
        patch_delete.short_description = "批量删除"
    
    
        def edit(self, obj=None, header=False):
            if header:
                return "操作"
    
            _url = self.get_change_url(obj)
            return mark_safe("<a href='%s'>编辑</a>" % _url)
    
        def deletes(self, obj=None, header=False):
            if header:
                return '操作'
    
            _url = self.get_delete_url(obj)
            return mark_safe("<a href='%s'>删除</a>" % _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='%s'>" % obj.pk)
    
        def get_modelform_class(self):
            if not self.modelform_class:
                class ModelFormDemo(ModelForm):
                    class Meta:
                        model = self.model
                        fields = "__all__"
                return ModelFormDemo
            else:
                return self.modelform_class
    
        def add_view(self, request):
            ModelFormDemo = self.get_modelform_class()
            form = ModelFormDemo()
            
            for bfield in form:
                print('i::', type(bfield))  # 字段类型
                # print('i::', bfield.field)  # 字段对象
                # print('name', bfield.name)  # 字段名字符串 publish authors
    
                # <class 'django.forms.boundfield.BoundField'>
                from django.forms.boundfield import BoundField
                print(bfield.field)
                from django.forms.models import ModelChoiceField
                from django.forms.models import ModelMultipleChoiceField
                # <django.forms.fields.CharField object at 0x0000014BD355EBA8>
                # <django.forms.models.ModelChoiceField object at 0x0000014BD355ECF8>
                # <django.forms.models.ModelMultipleChoiceField object at 0x0000014BD355ED68>
                from django.forms.models import ModelChoiceField
                if isinstance(bfield.field, ModelChoiceField):
                    bfield.is_pop = True
    
                    print('---',bfield.field.queryset.model)
                    # <class 'app01.models.Publish'>
                    # <class 'app01.models.Author'>
                    related_model_name = bfield.field.queryset.model._meta.model_name
                    related_app_label = bfield.field.queryset.model._meta.app_label
                    _url = reverse("%s_%s_add" % (related_app_label, related_model_name))
                    bfield.url = _url + "?pop_res_id=id_%s" % bfield.name
    
            if request.method == 'POST':
                form = ModelFormDemo(request.POST)
                if form.is_valid():
                    obj = form.save()
    
                    # 两种情况
                    pop_res_id = request.GET.get('pop_res_id')
                    if pop_res_id:
                        res = {"pk":obj.pk, 'text':str(obj), "pop_res_id": pop_res_id}
                        return render(request,'pop.html',{"res":res})
                    else:
                        return redirect(self.get_list_url())
    
            return render(request, 'add_view.html', locals())
    
        def delete_view(self, request, delete_id):
            url = self.get_list_url()
    
            if request.method == 'POST':
                self.model.objects.filter(pk=delete_id).delete()
                return redirect(url)
    
            return render(request, 'delete_view.html', locals())
    
        def change_view(self, request, change_id):
            ModelFormDemo = self.get_modelform_class()
            edit_obj = self.model.objects.filter(pk=change_id).first()
            form = ModelFormDemo(instance=edit_obj)
    
            if request.method == "POST":
                form = ModelFormDemo(request.POST, instance=edit_obj)
                if form.is_valid():
                    form.save()
                    return redirect(self.get_list_url())
    
            return render(request,'change_view.html', locals())
    
        def new_list_play(self):
            temp = []
            temp.append(ModelStark.checkbox)
            temp.extend(self.list_display)
            temp.append(ModelStark.edit)
            temp.append(ModelStark.deletes)
    
            return temp
    
        def new_actions(self):
            temp = []
            temp.append(ModelStark.patch_delete)
            temp.extend(self.actions)
    
            return temp
    
        def get_change_url(self, obj):
            model_name = self.model._meta.model_name
            app_lable = self.model._meta.app_label
    
            _url = reverse("%s_%s_change" % (app_lable, model_name), args=(obj.pk,))
    
            return _url
    
        def get_delete_url(self, obj):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,))
    
            return _url
    
        def get_add_url(self):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_add" % (app_label, model_name))
    
            return _url
    
        def get_list_url(self):
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            _url = reverse("%s_%s_list" % (app_label, model_name))
    
            return _url
    
        def get_search_condition(self, request):
            key_words = request.GET.get('q', "")
            self.key_words = key_words
            search_connection = Q()
            if key_words:
                search_connection.connector = "or"
                for search_field in self.search_fields:
                    search_connection.children.append((search_field+"__contains", key_words))
    
            return search_connection
    
        def get_filter_condition(self, request):
            filter_condition = Q()   # 默认是 and 不是 or
            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":
                print("request.POST:",request.POST)
                # 'action': ['patch_init'], 'selected_pk': ['1', '2']
                action = request.POST.get('action')
                selected_pk = request.POST.getlist('selected_pk')
                action_func = getattr(self, action) # 反射
                queryset = self.model.objects.filter(pk__in=selected_pk)  # 秒!!!
                ret = action_func(request, queryset)
                # return ret
    
            # 获取searchd得Q对象
            search_connection = self.get_search_condition(request)
    
            # 获取filter得Q对象
            filter_condition = self.get_filter_condition(request)
    
            # 筛选当前表得所有数据
            data_list = self.model.objects.all().filter(search_connection).filter(filter_condition)
            
            # 展示数据
            showlist = ShowList(self, data_list, request)
    
            # 构建一个查看url
            add_url = self.get_add_url()
            return render(request, 'list_view.html',locals())
    
        def get_urls2(self):
            temp = []
    
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
    
            temp.append(url(r'add/', self.add_view, name="%s_%s_add" % (app_label, model_name)))
            temp.append(url(r'(d+)/delete/', self.delete_view, name="%s_%s_delete" % (app_label, model_name)))
            temp.append(url(r'(d+)/change/', self.change_view, name="%s_%s_change" % (app_label, model_name)))
            temp.append(url(r'^$', self.list_view, name="%s_%s_list" % (app_label, model_name)))
    
            return temp
    
        @property
        def urls2(self):
    
            return self.get_urls2(), None, None
    
    
    class StarkSite(object):
        def __init__(self):
            self._registry = {}
    
        def register(self, model, stark_class=None):
            if not stark_class:
                stark_class = ModelStark
    
            self._registry[model] = stark_class(model,self)
    
    
        def get_urls(self):
            temp = []
            
            # 模型表,配置类对象
            for model, stark_class_obj in self._registry.items():
                model_name = model._meta.model_name
                app_label = model._meta.app_label
    
                # 分发增删改查
                temp.append(url(r'%s/%s/'%(app_label,model_name), stark_class_obj.urls2))
    
            return temp
    
        @property
        def urls(self):
    
            return self.get_urls(), None, None
    
    
    site = StarkSite()
    stark.py

    add_view.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
        <script src="/static/js/jquery-1.12.4.min.js"></script>
        <style type="text/css">
            input,select {
                display: block;
                width: 100%;
                height: 34px;
                padding: 6px 12px;
                font-size: 14px;
                line-height: 1.42857143;
                color: #555;
                background-color: #fff;
                background-image: none;
                border: 1px solid #ccc;
                border-radius: 4px;
                -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
                box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
                -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
                -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
                transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
            }
            .error{
                color: red;
            }
    
        </style>
    
    </head>
    <body>
    <h3>添加页面</h3>
    
    {% include 'form.html' %}
    
    <script type="text/javascript">
        function pop_response(pk, text,pop_res_id) {
            console.log(pk);
            console.log(text);
            console.log(pop_res_id);
    
             // optiond得文本值 和value
            var $option = $("<option>"); //<option></option>
            $option.html(text);
            $option.val(pk);
            $option.attr('selected','selected');
    
            $('#'+pop_res_id).append($option)
        }
    
    </script>
    
    </body>
    </html>
    add_view.html

    form.html

    <div class="container">
        <div class="row">
            <div class="col-md-6 col-xs-10 col-md-offset-1">
                <form action="" method="post" novalidate>
                    {% csrf_token %}
                    {% for field in form %}
                        <div style="position: relative">
                            <label for="">{{ field.label }}</label>
                            {{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
    
                            {% if field.is_pop %}
                                <a onclick="pop('{{ field.url }}')"><span style="font-size: 23px;position: absolute; right: -23px; top: 25px;">+</span></a>
                            {% endif %}
    
                        </div>
                    {% endfor %}
    
                    <button type="submit" class="btn btn-info">btn</button>
                </form>
    
            </div>
        </div>
    
    </div>
    <script type="text/javascript">
        function pop(url) {
            window.open(url,"","width=500,height=300,top=100,left=100")
        }
    </script>
    form.html

    pop.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <script type="text/javascript">
        window.opener.pop_response("{{ res.pk}}","{{ res.text }}","{{ res.pop_res_id }}");
        window.close()
    
    </script>
    
    </body>
    </html>
    pop.html

    三、stark - 总结

    总结

    (单例,继承,反射,面向对象,modelform 应用得很好!!)

    1.注册表
    单例模式 site = StarkSite()

    2.生成url
    url(r'^stark/', ([],None,None))

    3.数据列表展示
    可自定义配置显示:
    list_display = ["__str__"]
    list_display_links = []
    modelform_class = []
    search_fields = []
    actions = []
    list_filter = []

    4.增删改页面 modelform

    5.分页
    自定义分页组件 stark/utils/page.py
    class Pagination(object):
    ...
    ...

    6.search模糊查询
    Q查询 or
    search_connection = Q()
    ...
    data_list = self.model.objects.all().filter(search_connection)

    7.action批量处理
    def patch_init(self, request, queryset):
    queryset.update(price=123)
    ...
    patch_init.short_description = "批量初始化"

    actions = [patch_init]

    queryset = self.model.objects.filter(pk__in=selected_pk)

    8.filter过滤
    list_filter = ['title','publish', 'authors']
    eg:{"publish":["<a href=''>全部</a>","<a href=''>南京出版社</a>","<a href=''>上海出版社</a>"]
    "authors":["<a href=''>全部</a>","<a href=''>yuan</a>","<a href=''>egon</a>"]
    }

    Q查询 and
    filter_condition = Q()
    data_list = self.model.objects.all().filter(search_connection).filter(filter_condition)

    9.pop弹出
    在一对多和多对多字段后渲染 +
    +对应的跳转路径
    保存添加记录同时,将原页面的对应的下拉菜单中添加该记录

    test.py

    from django.test import TestCase
    
    # Create your tests here.
    
    #
    # class  A(object):
    #
    #     x=12
    #     def __init__(self,m):
    #         self.z = m
    #     def xxx(self):
    #         print(self.x)
    #         print(self.z)
    #
    # class B(A):
    #     x=5
    #     z = 11
    #
    # b=B(10)
    # b.xxx()
    
    #######################################
    #
    # class Person(object):
    #     def __init__(self,name):
    #         self.name = name
    #
    # alex = Person('alex')
    # print(alex.name)
    #
    # s = 'name'
    #
    # # print(alex.s)  # 用反射
    #
    # getattr(alex,s)
    #
    # print(getattr(alex,s))
    
    #######################################
     # 没学面向对象之前,都是函数 ,
    
    # 函数 方法
    
    # class Person(object):
    #     def __init__(self,name):
    #         self.name = name
    #
    #     def eat(self):  # 方法!
    #         print(self)
    #         print('eating...')
    #
    # # 实例方法
    # # egon = Person('egon')
    # # egon.eat()
    #
    # # 函数
    # Person.eat('ss')
    
    #######################################
    
    # list = [1,2,3]
    # list.append(4)
    # print(list)
    # list.insert(0,100)
    # print(list)
    
    #######################################
    # li = []
    # print(len(li))
    #
    # s = "sss"
    # print(isinstance(s,str))
    
    #######################################
    
    # class Person(object):
    #     def __init__(self,name):
    #         self.name = name
    #
    #     def __str__(self):
    #         return self.name
    #
    # alex = Person('alex')
    # # print(alex.name)
    # # print(alex)
    #
    # print(alex.__str__())
    # print(str(alex))
    #
    # print(getattr(alex,'__str__')())
    
    
    #######################################
    # temp = []
    # temp.append(1)
    # temp.extend([1,2,3])
    # print(temp)
    
    #######################################
    
    # def foo():
    #     return
    #
    # print(foo.__name__)
    
    
    #######################################
    # 查询是字段名称
    # Book.objects.filter(Q(title='yuan')|Q(price='123'))
    
    # Q() 查询放str,
    # q = Q()
    # q.connection = 'or'
    # q.children.append(('title','yuan'))
    # q.children.append(('price',123))
    
    #######################################
    
    # ret = self.model.objects.filter(title__startswith='py')
    # ret = self.model.objects.filter(price__in=[123, 111, 21, 11])
    # ret = self.model.objects.filter(price__range=[10, 100])
    # ret = self.model.objects.filter(title__contains='y')
    # ret = self.model.objects.filter(title__contains='o')
    # ret = self.model.objects.filter(title__icontains='o')
    # print(ret)
    # return HttpResponse('ok')
    
    #######################################
    
    # def foo():
    #     print('ok')
    #
    # print(foo.__name__)
    # print(type(foo.__name__))
    # foo.desc = '123'
    # print(foo.desc)
    # a = foo()
    # a.desc = 12
    # print(a.desc)
    
    #######################################
    
    # class A():
    
    # str = "http://127.0.0.1:8000/stark/app01/book/?publish=1&author=5"
    
    #######################################
    # class A(object):
    #     pass
    # 
    # class B(A):
    #     pass
    # 
    # b = B()
    # print(isinstance(b,A)) # True
    # print(isinstance(b,B)) # True
    test.py

    code

    原始版

      https://github.com/alice-bj/stark_pro_0

    简洁版

      https://github.com/alice-bj/stark_admin

  • 相关阅读:
    spring-mvc访问本地html文件
    好文收集
    jsp参数乱码解决
    ext window嵌jsp页面自适应
    正则学习(转)
    Error occurred during initialization of VM Incompatible initial and maximum heap sizes specified
    产品测试流程
    创建maven工程时报错,解决方案
    接口测试中如何利用cookies保持会话
    http协议基础
  • 原文地址:https://www.cnblogs.com/alice-bj/p/9215024.html
Copyright © 2020-2023  润新知