##今日更新内容

#1、search_field
    需要掌握技术点
        Q查询
            1.直接用Q去查
            
            2.    from app01 import models
                models.Book.objects.filter(title__contains='',price__contains=2)
                <QuerySet []>
                from django.db.models import Q
                models.Book.objects.filter(Q(title__contains='')|Q(price__contains=2))
                <QuerySet [<Book: 三国演义>]>
                models.Book.objects.filter(Q(title__contains='')|Q(price__contains=8))
                <QuerySet [<Book: 红楼梦>, <Book: 三国演义>]>
                q = Q()
                q.children.append(('title__contains',''))  # 添加查询条件
                q.children.append(('price__contains',8))
                models.Book.objects.filter(q)
                <QuerySet [<Book: 三国演义>]>
                q.connector = 'or'  # q对象默认也是and关系 但是可以通过connector修改成or的关系
                models.Book.objects.filter(q)
                <QuerySet [<Book: 红楼梦>, <Book: 三国演义>]>
#2、actions
    实现批处理操作,当用户选中相对应的check框,选择相应的批处理操作(如:更新、删除等)进行统一操作
#3、list_filter
        1.显示外键字段 及外键字段所对应的模型表中的所有的数据
            获取外键字段所对应的模型表变量名
            models.Book._meta.get_field('publish').rel.to
        2.{'publish':[publish_obj,publish_obj1,]}
        3.给数据对象简单的配置href链接
        4.深拷贝request.GET 完成自动保存get携带的参数的功能
        5.点击标签后 样式变换 
        6.all标签
        7.后端还是利用q对象进行数据过滤  直接用默认的and关系
        
    需要掌握技术点
        #获取外键字段对应的表变量名,field是字段的字符串形式,该方法能根据他获取表名
        rel_model = self.config_obj.model._meta.get_field(field).rel.to
    
#4、pop功能:父子页面如何通信? doc操作创建option标签
    需要解决的问题:
        1、在添加操作页面在外键字段右边添加一个加号,那后端怎么判断哪一个字段是外键字段
            解决方案:
                循环模型表、拿到一个个对象,判断对象是否是,如果是,就给过滤的对象添加额外的属性,用于前端渲染的时候
                根据是否存在这个额外添加的属性进行判断,判断通过就在外键字段后面添加+加号。
        2、给加号绑定点击事件、当点击加号时要跳转到对应外键表的添加页面,那后端要动态传对应不同表的添加页面的url,之前
            二级url是怎么拼接来着?
                后端:
                # print(form_obj.name) #拿到外键字段publish 、authors
                rel_model = self.model._meta.get_field(form_obj.name).rel.to #通过字段名拿到所对应的模型表
                rel_app_label = rel_model._meta.app_label #通过模型表拿到所对应的应用名
                rel_model_name = rel_model._meta.model_name #通过模型表拿到所对应的模型表名
                url = reverse('%s_%s_%s'%(rel_app_label,rel_model_name,'add'))
                form_obj.url = url  #这里给对象添加属性,前端直接可以使用,这种方法牢记,解决前后端数据传递问题
        3、如何区分你子页面添加数据还是正常窗口添加页面?怎么理解呢?
            问题:当在添加书籍book页面,点击加号跳转小窗口到对应的authos页面或者出版社publish小窗口页面,添加完数据后,不能直接
                  返回的是author页面 而是自动关闭小窗口,继续进行book页面添加操作,而且选择下拉框默认选中你所创建的作者或者出版社
                  信息。
            解决方案:
                为了识别父页面子页面,在打开子页面的url后面加get请求参数,获取form_obj渲染的标签id值form_obj.auto_id,然后拼接到
                get请求url后面,这样子页面添加请求时通过url就能识别,当时别子页面以后,要return render(request,'stark/pop.html',locals()) 
                在新子页面中要直接关闭子页面操作,再关闭之前还要调用父页面方法,不管是单标签还是多标签,
        4、父页面要干什么?父页面需要自动渲染一个option标签
            这里就学到了document创建option标签的方法,思考渲染标签需要什么数据?子页面pop.html怎么调用父页面add_view.html使用了
                子页面可以调用父页面中的方法
                    window.opener.fatherFunc(...)
                    window.close()
                父页面创建option标签:
                     function addOptions(pop_back_id,pk,text) {
                        //动态创建option标签  想想创建标签需要什么参数,不过函数比较好写的原因是所需要什么参数
                        //先定义形参就可以,到时谁调用谁给我传过来
                        var optEle = document.createElement('option');
                        //给标签赋属性
                        optEle.innerText = text;
                        optEle.value = pk;
                        optEle.selected = 'selected';//默认选中
                        //查找option所在的父标签
                        var seEle = document.getElementById(pop_back_id);
                        seEle.appendChild(optEle)

                    }

  ##search_field:或查询条件

#自定义配置类中:
    class BookConfig(ModelStark):
        search_fields = ['title','price'] #自定义search_fields查询条件 且为or条件
#默认配置类中
    class ModelStark(object):
        #ModelStark中时默认的参数,用户自定义的的在C:\starkpro\app01\stark.py
        list_display = ['__str__',]
        list_display_links = []
        model_form_class = None
        search_fields = [] #默认search_fields
        def __init__(self,model):
            self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样
            self.app_label = self.model._meta.app_label  #直接给对象初始化应用名
            self.model_name = self.model._meta.model_name #直接给对象初始化表名
            self.key_word = '' #初始化
        def list_view(self, request):
            #查看self.model  <class 'app01.models.Book'> 那张表查看就代表谁
            # print(self.model)

            queryset = self.model.objects.all()
            #search_file功能
            key_word = request.GET.get('q') #接受前端传来的数据
            #先对key_word初始值进行清空操作
            self.key_word = ''
            if key_word:
                """
                需要解决问题:
                    1、变量名问题
                        前后端传递的是字符串,orm数据查询语句时需要的是字段
                    2、查询条件由and改为or(这里再说明一下django源码中默认admin五大参数中search_files是或查询条件)  
                解决方案:Q查询
                    Q查询有两种方法:
                        1、正常情况可以解决and 或者or 但是没法解决变量名问题
                        2、另一种用法
                            q = Q()
                            q.children.append(('title__contains','三'))  # 添加查询条件
                            q.children.append(('price__contains',8))
                            models.Book.objects.filter(q)
                            <QuerySet [<Book: 三国演义>]>
                            q.connector = 'or'  # q对象默认也是and关系 但是可以通过connector修改成or的关系
                            models.Book.objects.filter(q)
                            <QuerySet [<Book: 红楼梦>, <Book: 三国演义>]>
                        
                """
                self.key_word = key_word
                from django.db.models import Q
                q = Q() #创建q对象
                q.connector = 'or' #指定q查询条件
                #不停的往children中添加查询条件
                for search_field in self.search_fields: #在自定义配置类中serch_fields = ['title','price']
                    print(search_field)
                    q.children.append(('%s__icontains'%search_field,key_word))  #contains为包含  价格i忽略大小写
                queryset = queryset.filter(q)
            #展示类调用
            show_obj = ShowList(self,queryset,request)


            url = self.get_reverse_url('add')
            return render(request,'stark/list_view.html',locals())
#前端list_view.html
{% extends 'stark/base.html' %}
{% block content %}
    <h2 class="text-center">数据展示</h2>
    <div class="col-md-8 col-md-offset-2">
        <a href="{{ url }}" class="btn btn-primary">添加数据</a>
        {% if show_obj.config_obj.search_fields %}
            <form class="form-inline pull-right">
            <div class="form-group">
                <div class="input-group">
                    <input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q" value="{{ show_obj.config_obj.key_word }}">
                </div>
            </div>
            <button type="submit" class="btn btn-primary">Search</button>
        </form>
        {% endif %}
        <table class="table table-striped table-bordered table-hover">
            <thead>
            <tr>
                {% for foo in show_obj.get_header %}
                    <td>{{ foo }}</td>
                {% endfor %}
            </tr>
            </thead>
            <tbody>
            {% for body in show_obj.get_body %}
                <tr>
                    {% for  foo in body %}
                        <td>
                            {{ foo }}
                        </td>
                    {% endfor %}
                </tr>
            {% endfor %}
            </tbody>

        </table>
        {{ show_obj.page_obj.page_html|safe }}
    </div>
{% endblock %}
View Code

  ##actions批处理功能

#前端 list_view.html
{% extends 'stark/base.html' %}
{% block content %}
    <h2 class="text-center">数据展示</h2>
    <div class="col-md-8 col-md-offset-2">
        <a href="{{ url }}" class="btn btn-primary">添加数据</a>
        {% if show_obj.config_obj.search_fields %}
            <form class="form-inline pull-right">
            <div class="form-group">
                <div class="input-group">
                    <input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q" value="{{ show_obj.config_obj.key_word }}">
                </div>
            </div>
            <button type="submit" class="btn btn-primary">Search</button>
        </form>
        {% endif %}
         <form action="" method="post" class="form-inline">
            {% csrf_token %}
            <select name="action" id="" class="form-control">

                <option value="">--------------------------</option>
                {% for foo in show_obj.get_actions %}
                    <option value="{{ foo.name }}">{{ foo.desc }}</option>
                {% endfor %}

            </select>
            <input type="submit" value="GO" class="btn btn-danger">
            <table class="table table-striped table-bordered table-hover">
            <thead>
            <tr>
                {% for foo in show_obj.get_header %}
                    <td>{{ foo }}</td>
                {% endfor %}
            </tr>
            </thead>
            <tbody>
            {% for body in show_obj.get_body %}
                <tr>
                    {% for  foo in body %}
                        <td>
                            {{ foo }}
                        </td>
                    {% endfor %}
                </tr>
            {% endfor %}
            </tbody>

        </table>
        </form>

        {{ show_obj.page_obj.page_html|safe }}
    </div>
{% endblock %}

#自定义配置类C:\starkpro\app01\stark.py
class BookConfig(ModelStark):
    def patch_init(self,request,queryset):
        queryset.update(price=888)

    patch_init.desc = '价格批量处理'
    def patch_delete(self,request,queryset):
        queryset.delete()
    patch_delete.desc = '价格批量删除'
    actions = [patch_init,patch_delete]
#默认配置类
class ModelStark(object):
    #ModelStark中时默认的参数,用户自定义的的在C:\starkpro\app01\stark.py
    list_display = ['__str__',]
    list_display_links = []
    model_form_class = None
    search_fields = []
    actions = []  #添加一个默认action
    
    def check_box(self,is_header=False,obj=None):
        if is_header:
            return '选择'
        #添加每一个check的id值,以便用户选中后后台需要获取
        return mark_safe('<input type="checkbox" value="%s" name="selected_action"/>'%obj.pk) 
    def list_view(self, request):
        #查看self.model  <class 'app01.models.Book'> 那张表查看就代表谁
        # print(self.model)

        if request.method == 'POST':
            #获取用户选中的函数字符串名
            action = request.POST.get('action')
            #获取用户选中的逐渐字段
            pk_list = request.POST.getlist('selected_action')
            #根据主键字段查询所有的数据
            queryset_list = self.model.objects.filter(pk__in=pk_list)
            #通过反射由函数字符串找函数名
            real_action = getattr(self,action) #这里self是指用户自定义的self
            #将queryset对象传给函数处理
            real_action(request,queryset_list)
        queryset = self.model.objects.all()
        queryset = self.search(queryset,request)
        #展示类调用
        show_obj = ShowList(self,queryset,request)


        url = self.get_reverse_url('add')
        return render(request,'stark/list_view.html',locals())
#展示类
class ShowList:
    def get_actions(self):
        tmp_list = [] #actions = [patch_init]
        for action in self.config_obj.actions: #循环用户自定义ations列表
            tmp_list.append({
                'name':action.__name__,#字符串对应的名字
                'desc':action.desc
            })
        return tmp_list  #[{'name':'','desc':''}]
View Code

  ##filter前端渲染和筛选功能

#自定义配置类
class BookConfig(ModelStark):
    list_filter = ['publish','authors']

#默认配置类
class ModelStark(object):
    list_filter=[]
    def list_view(self, request):
        #查看self.model  <class 'app01.models.Book'> 那张表查看就代表谁
        # print(self.model)

        if request.method == 'POST':
            #获取用户选中的函数字符串名
            action = request.POST.get('action')
            #获取用户选中的逐渐字段
            pk_list = request.POST.getlist('selected_action')
            #根据主键字段查询所有的数据
            queryset_list = self.model.objects.filter(pk__in=pk_list)
            #通过反射由函数字符串找函数名
            real_action = getattr(self,action) #这里self是指用户自定义的self
            #将queryset对象传给函数处理
            real_action(request,queryset_list)
        queryset = self.model.objects.all()
        queryset = self.search(queryset,request)
        #filter功能 list_filter=['publish','authors']
        q = Q()
        for field in self.list_filter:
            if field in request.GET:
                filter_value = request.GET.get(field)
                q.children.append((field,filter_value))
        queryset = queryset.filter(q)
        #展示类调用
        show_obj = ShowList(self,queryset,request)


        url = self.get_reverse_url('add')
        return render(request,'stark/list_view.html',locals())
#展示类
class ShowList:
    def get_filter(self):
        tmp_dict = {}
        for field in self.config_obj.list_filter: #用户自定配置数据格式为list_filter = ['publishs','authors']
            tmp_list = []
            #获取外键字段对应的表变量名,field是字段的字符串形式,该方法能根据他获取表名
            rel_model = self.config_obj.model._meta.get_field(field).rel.to
            rel_queryset = rel_model.objects.all()
            filter_value = self.request.GET.get(field)
            import copy
            """
            渲染前端ALL标签
                点击ALL 标签,使当前所在的字段从访问网址中删除掉
            """
            params1 = copy.deepcopy(self.request.GET)
            if field in params1:
                params1.pop(field)
                s = mark_safe("<a href='?%s'>ALL</a>"%params1.urlencode())
            else:
                s=mark_safe("<a href=''>ALL</a>")
            tmp_list.append(s)
            """
            下面渲染每一个表对象下的字段
            """
            params = copy.deepcopy(self.request.GET)
            for obj in rel_queryset:
                params[field] = obj.pk #将每一个对象对应的id存到字典中
                if filter_value == str(obj.pk):
                    #如果该标签被点击了,为了显示为红色,利用条件来添加一个action类属性
                    s = mark_safe('<a href="?%s" class="active">%s</a>' % (params.urlencode(), str(obj)))
                else:
                    #params.urlencode() 将存入的对象以?publish=1&authors=1方式读出来,即前端访问网址能保存搜索条件了
                    s = mark_safe('<a href="?%s">%s</a>'%(params.urlencode(),str(obj)))
                tmp_list.append(s)
            tmp_dict[field] = tmp_list #{'publishs':[obj1,obj2],'authors':[obj1,obj2]}
        return tmp_dict
        
#前端list_view.html
{% extends 'stark/base.html' %}
{% block content %}
    <h2 class="text-center">数据展示</h2>
    <div class="col-md-9 ">
        <a href="{{ url }}" class="btn btn-primary">添加数据</a>
        {% if show_obj.config_obj.search_fields %}
            <form class="form-inline pull-right">
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q"
                               value="{{ show_obj.config_obj.key_word }}">
                    </div>
                </div>
                <button type="submit" class="btn btn-primary">Search</button>
            </form>
        {% endif %}
        <form action="" method="post" class="form-inline">
            {% csrf_token %}
            <select name="action" id="" class="form-control">
                <option value="">--------------------------</option>
                {% for foo in show_obj.get_actions %}
                    <option value="{{ foo.name }}">{{ foo.desc }}</option>
                {% endfor %}

            </select>
            <input type="submit" value="GO" class="btn btn-danger">
            <table class="table table-striped table-bordered table-hover">
                <thead>
                <tr>
                    {% for foo in show_obj.get_header %}
                        <td>{{ foo }}</td>
                    {% endfor %}
                </tr>
                </thead>
                <tbody>
                {% for body in show_obj.get_body %}
                    <tr>
                        {% for  foo in body %}
                            <td>
                                {{ foo }}
                            </td>
                        {% endfor %}
                    </tr>
                {% endfor %}
                </tbody>

            </table>
        </form>

        {{ show_obj.page_obj.page_html|safe }}
    </div>
    <div class="col-md-3">
        {% if show_obj.config_obj.list_filter %}
            <div class="alert-info text-center">FILTER</div>
            {% for k,v in show_obj.get_filter.items %}
                <div class="panel panel-default">
                    <div class="panel-heading">By {{ k }}</div>
                    <div class="panel-body">
                        {% for foo in v %}
                            <p>{{ foo }}</p>
                        {% endfor %}

                    </div>
                </div>
            {% endfor %}
        {% endif %}
    </div>
{% endblock %}
View Code

  ##pop功能:父子页面如何通信?怎么定义自动创建option标签函数?

#默认配置类
class ModelStark(object):
    def add_view(self, request):
        model_form_class = self.get_model_form()
        model_form_obj = model_form_class()
        if request.method == 'POST':
            model_form_obj = model_form_class(request.POST)
            pop_back_id = request.GET.get('pop_back_id')
            if model_form_obj.is_valid():
                obj = model_form_obj.save() #保存以后能拿到一个对象
                if pop_back_id: #如果pop_back_id有值 说明是子页面提交过来的post请求
                    #给子页面传创建option标签所需要的参数
                    pk = obj.pk
                    text = str(obj)
                    return render(request,'stark/pop.html',locals()) #如果是子页面 渲染一个新页面
                return redirect(self.get_reverse_url('list'))
        #渲染外键字段后面添加加号
        from django.forms.models import ModelChoiceField
        for form_obj in model_form_obj:
            if isinstance(form_obj.field,ModelChoiceField):
                form_obj.is_pop = True
                # print(form_obj.name) #拿到外键字段publish 、authors
                rel_model = self.model._meta.get_field(form_obj.name).rel.to #通过字段名拿到所对应的模型表
                rel_app_label = rel_model._meta.app_label #通过模型表拿到所对应的应用名
                rel_model_name = rel_model._meta.model_name #通过模型表拿到所对应的模型表名
                url = reverse('%s_%s_%s'%(rel_app_label,rel_model_name,'add'))
                # print(form_obj.auto_id) #拿到当前 input渲染的id值 id_publish、id_authors
                url = url +'?pop_back_id=%s'%form_obj.auto_id
                form_obj.url = url
        return render(request, 'stark/add_view.html', locals())
#前端:add_view.html  渲染外键添加加号 和绑定点击事件跳出小窗口  和 定义自动创建option标签函数
{% extends 'stark/base.html' %}
{% block css %}
    <link rel="stylesheet" href="/static/css/my_css.css">
{% endblock %}
{% block content %}
    <div class="col-md-6 col-md-offset-3">
            <h2 class="text-center">添加数据</h2>
            <form action="" method="post">
                {% csrf_token %}
                {% for form_obj in model_form_obj %}
                    <div class="plus-father">
                        <p>{{ form_obj.label }}{{ form_obj }}
                        <span>{{ form_obj.error.0 }}</span>
                    </p>
                    <div>
                        {% if form_obj.is_pop %}
                            <span class="plus" onclick="WindowOpen('{{ form_obj.url }}')">+</span>
                        {% endif %}
                    </div>
                    </div>

                {% endfor %}
                <input type="submit" class="btn btn-success pull-right">
            </form>
        </div>

    <script>
        //绑定点击函数, window.open跳出子页面,url为动态数据,应该怎么获取这个是个难点
        function WindowOpen(url){
            window.open(url,'','width=800px,height=400px')
        }
        function addOptions(pop_back_id,pk,text) {
            //动态创建option标签  想想创建标签需要什么参数,不过函数比较好写的原因是所需要什么参数
            //先定义形参就可以,到时谁调用谁给我传过来
            var optEle = document.createElement('option');
            //给标签赋属性
            optEle.innerText = text;
            optEle.value = pk;
            optEle.selected = 'selected';//默认选中
            //查找option所在的父标签
            var seEle = document.getElementById(pop_back_id);
            seEle.appendChild(optEle)

        }
    </script>
{% endblock %}
#前端:base.html  使用相对绝对位置调节加号位置
 <style>
        table{
            margin-top: 10px;
        }
        .active{
            color: red;
        }
        .plus-father{
            position: relative;
        }
        .plus{
            font-size: 24px;
            color: #369;
            position: absolute;
            right: -20px;
            top: 20px;

        }
    </style>
#前端:pop.html  关闭子页面 和 调用父页面自动创建option函数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bs-3.3.7/css/bootstrap.css">
    <script src="/static/bs-3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<script>
    //调用父页面add_view.html函数,为父页面自动创建option标签,创建该标签所需要的参数,从后端拿,想想都需要哪些参数
    //这些参数从后端该怎么拿
    window.opener.addOptions('{{ pop_back_id }}','{{ pk }}','{{ text }}');
    window.close() //为父页面渲染option标签后,主动关闭子页面
</script>
</body>
</html>
View Code

 

posted on 2019-08-06 16:12  Icon-Liang  阅读(251)  评论(0编辑  收藏  举报