• Xadmin查询


    目录

    深浅coopy运用

    为什么在类中引用函数不用self 而是用类名调用

       
       def search_boutton(self,obj=None,header=False):
            if header:
                return "操作"
            else:
                url = reverse("%s_%s_update"%(self.app_name,self.table_name),args=[obj.pk,])      # 反向解析
                return mark_safe("<a href='%s'>编辑</a>" % url)
       
       
       
       
       
        def rebulid_display_list(self):
            tem=[]
            tem.append(ModelXadmin.checkbox_button)         # 把选择框加到表头和表单前面,
                   # 之所以用类,是因为在缺省形参中,如果调用一次,之后的参数都会发生改变,
            tem.extend(self.list_display)     # 把实例化对象自身的数据加到tem当中
    
            if not self.list_display_link:     # 是否传有link项
                tem.append(ModelXadmin.search_boutton)
            tem.append(ModelXadmin.delete_button)         # 把选择框加到表头和表单前面,
    
            return tem
    

    这是因为函数中有缺省参数,如果 用self调用,就会指向自己的方法内,缺省参数有一次改变,之后的调用都是指向该值,即参数会改变,而函数则是不一样,他的缺省参数,默认的是原始值.

    ModelForm的补充

        def get_models_form(self):
            if not self.Model_Form_class:
                class Model_Form(ModelForm):
                    class Meta:
                        model = self.model
                        fields = "__all__"
                        labels = {
                            ""
                        }
                return  Model_Form      # 查看列表,即主页,并对相应字段配上路径
            else:
                return self.Model_Form_class
    

    提取模型当中相关属性

    getattr和get_field的区别

    getattr主要是提取对象当中的属性,切记是对象属性

    class Article(models.Model):
        """
        文章
        """
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=50, verbose_name="文章标题")  # 文章标题
        desc = models.CharField(max_length=255,verbose_name="文章简述")  # 文章描述
        create_time = models.DateTimeField(verbose_name="创建时间",auto_now_add=True)  # 创建时间
    
        # 评论数
        comment_count = models.IntegerField(verbose_name="评论数", default=0)
        # 点赞数
        up_count = models.IntegerField(verbose_name="点赞数", default=0)
        # 踩
        down_count = models.IntegerField(verbose_name="踩数", default=0)
    
        category = models.ForeignKey(to="Category", to_field="nid", null=True ,on_delete=models.CASCADE,verbose_name="分类")
        user = models.ForeignKey(to="UserInfo", to_field="nid" ,on_delete=models.CASCADE,verbose_name="作者")
        tags = models.ManyToManyField(  # 中介模型
            to="Tag",
            through="Article2Tag",
            through_fields=("article", "tag"),  # 注意顺序!!!
            verbose_name="标签",
        )
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "文章"
            verbose_name_plural = verbose_name
    
    

    如下测试

    obj=models.Article.objects.filter(user=12).first()
       
    print("nid:",type(getattr(obj,"nid")))
    print("title:",type(getattr(obj,"title")))
    print("user:",type(getattr(obj,"user")))
    
    ----------------------------------------
    结果是:
    nid: <class 'int'>
    title: <class 'str'>
    user: <class 'app01.models.UserInfo'>
    

    也就是说其拿到的是对象的属性,如果是外键,也可以理解为当前字段存的是外键对象,nid相当于内存地址,

    get_field是针对models中模型使用的,主要目的是拿到该字段是由谁实例化的

    print(type(models.Article._meta.get_field("user")))
    
    print(type(models.Article._meta.get_field("tags")))
    ------------------------------------------
    结果是:
        <class 'django.db.models.fields.related.ForeignKey'>
        
        <class 'django.db.models.fields.related.ManyToManyField'>
    

    也就是说他拿到的是等号后面的类实例化对象

    ---------------------
    

    其次参数是不一样的,getattr第一个参数是对象,而_meta.get_field是django下面特有的方法

    而用getattr取对象中的双下划綫方法,就相当于执行函数拿到相应的值

    
    

    __ str__,get_field,getattr初识

    __str __,当用getattr进行取值,默认返回对象内的__str __内返回值

    class Tag(models.Model):
        """
        标签
        """
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32)  # 标签名
        blog = models.ForeignKey(to="Blog", to_field="nid" ,on_delete=models.CASCADE)  # 所属博客
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "标签"
            verbose_name_plural = verbose_name
    
    
    
    obj=models.Blog.objects.filter().first()
    getattr(obj,field)
    ---------------------------------
    结果是:
         self.title对应的值,因为双下划綫一定会执行的
    
    

    get_field(field _name)获取字段对应的对象,如title = models.CharField(max _length=32) ,我们获取到的是CharField实例化的对象,通过对象就可以拿到相应的参数值

     title_list.append(self.model._meta.get_field(field).verbose_name)  #求字段中文名
    

    getattr

    获取对象 object 的属性或者方法,若存在则打印出来;若不存在,则打印默认值,默认值可选。注意:如果返回的是对象的方法,那么打印的结果是方法的内存地址。如果需要运行这个方法,那么可以在后面添加括号 () 。

    函数对象名字提取

    def b():
        pass
    print(b.__name__)
    b.short="1233456"
    
    print(b.short)
    --------------------------    
    结果是:
        b
        1233456
    
    

    反向解析

    切记第二个参数是可迭代数据,因此否则会报错

        from django.urls import reverse
        def get_udate_url(self,obj):
            _url = reverse("%s_%s_update" % (self.app_name, self.table_name), args=[obj.pk, ])  # 反向解析
            return _url
    

    字符串标签安全布局

    from django.utils.safestring import mark_safe
    def checkbox_button(self,obj=None,header=False):
        if header:
            return  mark_safe("<label><input type='checkbox' name='check'  class='control_all'></label>")
        return  mark_safe("<label><input type='checkbox'   class='item_choice'></label>")
    

    保存当前传进来的路径,并跟新参数

    参数提取与更新,运用了django内置的转换格式.

    request.Get拿到的是字典形式参数   <QueryDict: {'page': ['7'], 'gt': ['10']}>
    request_params.urlencode()  把chuanjinlai的参数转化成page=7&gt=10
    

    HTML中还可以执行函数

    在HTML中执行函数

    class Show_list(object):
        def __init__(self,config,data_list):
            self.config=config
            self.data_list=data_list
    
        def get_TableHead(self):
            title_list = []
            for field in self.config.rebulid_display_list():
                if isinstance(field, str):
                    if field == "__str__":
                        title_list.append(self.config.table_name.upper())  # 如果传显示列表就返回表名
                    else:
                        title_list.append(self.config.model._meta.get_field(field).verbose_name)  # 求字段中文名
                else:  # if callable(field)   判断是不是函数                                                                 # 函数怎么命名
                    var = field(self.config, header=True)
                    title_list.append(var)  # 求函数名
    
            return title_list
        def get_TableBody(self):
            items_list = []
            for obj in self.data_list:            # 某一个字段对象
                item=[]
                for field in self.config.rebulid_display_list():        #["title","desc",add_0]  ["__str__"]
    
                       if not callable(field):
                            if field in self.config.list_display_link:
                                url = self.config.get_udate_url(obj)
                                item.append(mark_safe("<a href='%s'>%s</a>"%(url,getattr(obj,field))))
                            # 求字段名
                            else:
                                item.append(getattr(obj,field))        # 当是多对多的关系时,这个也可以的
                                                                    # 在模型表当中定义了__str__,执行或者打印都返回指定数据,原来是为这里服务
                       else:
                           item.append(field(self.config,obj))
                items_list.append(item)
            return  items_list
            
    
    
    def list_views(self, request, *args):
        data_list,paging_label=self.get_paging(request)
        show_list=Show_list(self,data_list)
        add_url=self.add_url()
        return render(request, "XXadmin/XXadmin_check.html",
                      {
                       "add_url":add_url,
                       "paging_label":paging_label,
                       "show_list":show_list
                      })
    

    html执行函数方法

    <table class="table">
            <thead>
            <tr>
            
            
                {% for title in show_list.get_TableHead %}
                    <th>{{ title }}</th>
                {% endfor %}
           
           
            </tr>
            </thead>
            <tbody>
            {% for foo in show_list.get_TableBody %}
                <!-- 拿到的是一个列表 -->
                <tr>
                
                
                    {% for item in foo %}
                        <td>{{ item }}</td>
                    {% endfor %}
                
                
                </tr>
            {% endfor %}
            </tbody>
    </table>
    

    xadmin功能实现

    批量处理方法

    自定义批量方法,并在表注册的时候存放在自定义的类中,然后以列表的形式把函数存放起来

    def delete_table(self,request,queryset):    #  删除数据
        queryset.delete()
    
    def update_table(self,request,queryset):    #  更新数据
        queryset.update()
        
    delete_table.shortdesc="批量删除"
    update_table.shortdesc="批量修改"
    
    action=[delete_table,update_table]
    # 注意函数也是对象,可以添加描述属性,目的是为了在HTML中显示该步骤是什么操作
    

    然后在Xadmin中调用该列表,取出相应方法,和描述,存放在一个列表当中,方便在HTML中循环显示

     self.action=[{"name": i.__name__,"desc":i.shortdesc} for i in  self.config.action] 
    

    最后在HTML中显示该操作方法

       <select name="action" id="action">
            <option value="">------------</option>
            
            {% for i in show_list.action %}
                <option value="{{ i.name }}">{{ i.desc }}</option>
            {% endfor %}
        </select>
    

    image

    因为是修改数据库操作,因此要用post请求,防止xss攻击

    在视图处理,因为在自定义的是时候没有前端传过来的action和要批量处理的数据,因此只能够定义删除方法

    def many_action(self,request,queryset):
        action = request.POST.get("action", "")
        action1 = getattr(self.config,action)
        action1(request, queryset)            #    批量处理时
    
    
    
    在views视图中调用该方法
    
    if request.method == "POST":
        condition = request.POST.getlist('item', "")
        queryset = self.model.objects.filter(pk__in=condition)
        show_list.many_action(request,queryset)
    

    **request.get或者request.post返回的是函数参数部分,或者是表单提交的数据 **

    还要注意get和get_list的区别

    返回全部数据
        condition = request.POST.getlist('item', "")
    只返回列表当中的最后一个
        condition = request.POST.get('item', "")
    

    搜索功能实现

    Q查询补充

    主要用到了Q查询的,字符串拼接法,条件的字符串

    传入条件进行查询:

    q1 = Q()
    q1.connector = 'OR'
    q1.children.append(('id', 1))
    q1.children.append(('id', 2))
    q1.children.append(('id', 3))
        
    models.Tb1.objects.filter(q1)
    

    合并条件查询

    con = Q()
    
    q1 = Q()
    q1.connector = 'OR'
    q1.children.append(('id', 1))
    q1.children.append(('id', 2))
    q1.children.append(('id', 3))
    
    q2 = Q()
    q2.connector = 'OR'
    q2.children.append(('status', '在线'))
    
    con.add(q1, 'AND')
    con.add(q2, 'AND')
    
    models.Tb1.objects.filter(con)
    

    主要思路是把搜索条件拼接在相应的a标签中,等到下一次查询时,就把相应的查询条件放在相应的a标签中,这时就会带着上一次查询条件进行查询,也就是说,每一次查询都会重新渲染页面

    分页代码中拼接条件,首先得用request.get求出所有参数,其是字典形式的参数,因此需要修改响应值可以通过

    注意在修改数据之前需要备份,防止在下一个函数处理数据时,会用到修改后的数据

            self.request_params=copy.deepcopy(request_get)            # 复制一份原有传进的的参数,不影响原有数据,当在函数下执行时
    
    

    因此在修改后的数据进行修改

    self.request_params["page"]=1
    

    对函数进行序列化,转换成url路径参数的形式

    {'action': ['delete_table'], 'check': ['on'], 'item': ['102', '103', '104', '105', '106', '107', '108', '109', '110', '111']}
    

    url特有的方法

    self.request_params.urlencode()
    
    action ='delete_table'&check=['on']&item=['102', '103', '104', '105', '106', '107', '108', '109', '110', '111']
    

    最后把相应的参数拼接到a标签当中即可,完成,条件保留

    紧接着就是条件拼接

    def search_contition(self,request):
        key_word=request.GET.get("key_word","") # key_word默认为空
        self.key_word=key_word
        contion = Q()
        contion.connector = "or"  # 改变q条件之间的关系为   or  关系
        if not self.search_list:
            pass
        else:
            for field in self.search_list:
                contion.children.append((field+"__contains",key_word))
        return contion
    
    
    con=search_contition(request)
    if con:    # 判断查询
        data_list=self.model.objects.filter(con)
    else:
        data_list=self.model.objects.all()    # 如何判断是查询还是分页,放在同一个条件中,看你有没有查询条件,没有则帅选全部数据
    
    
    
    {'csrfmiddlewaretoken': ['cNsATE1XfZLsG3h6fwBRYLtXgFaHGA5zOAny87XGqsvdNCI2B8hQENvedrjE86bB'], 'action': ['delete_table'], 'check': ['on'], 'item': ['102', '103', '104', '105', '106', '107', '108', '109', '110', '111']}
    

    分页中经典算法

    
            for i in range(self.page_start, self.page_end + 1):
                self.request_params["page"] = i
                if i == self.current_page:
                    tmp = '<li class="active"><a href="{0}?page={1}">{2}</a></li>'.format(self.current_url,self.request_params.urlencode(), i)
                else:
                    tmp = '<li><a href="{0}?{1}">{2}</a></li>'.format(self.current_url,self.request_params.urlencode(),i)                   # 把字典转换成等式,i)
                l.append(tmp)
             # request.Get拿到的是字典形式参数   <QueryDict: {'page': ['7'], 'gt': ['10']}>
             # request_params.urlencode()  把chuanjinlai的参数转化成page=7&gt=10
    
                # 加一个下一页上一页,首页,末页
            if self.total_page:
                if self.current_page == 1 and self.total_page==1:
                    l.insert(0,'<li class="disabled" ><a href="#">«</a></li>')
                    l.append('<li class="disabled"><a href="#">»</a></li>')
                elif self.current_page==1:
                    l.insert(0, '<li class="disabled" ><a href="#">«</a></li>')
                    self.request_params["page"] =  self.current_page + 1
                    l.append('<li><a href="{}?{}">»</a></li>'.format(self.current_url,self.request_params.urlencode()))
                elif self.total_page==self.current_page:
                    self.request_params["page"] = self.current_page - 1
                    l.insert(0, '<li ><a href="{}?{}">«</a></li>'.format(self.current_url,self.request_params.urlencode()))
                    self.request_params["page"] = self.total_page
                    l.append('<li class="disabled"><a href="{0}?{1}">»</a></li>'.format(self.current_url,self.request_params.urlencode() ))
                else:
                    self.request_params["page"] = self.current_page - 1
                    l.insert(0, '<li ><a href="{0}?{1}">«</a></li>'.format(self.current_url,self.request_params.urlencode()))
    
                    self.request_params["page"] = self.current_page + 1
                    l.append('<li><a href="{0}?{1}">»</a></li>'.format(self.current_url, self.request_params.urlencode()))
    
                self.request_params["page"] =1
                l.insert(0, '<li ><a href="{}?{}">首页</a></li>'.format(self.current_url,self.request_params.urlencode()))
                self.request_params["page"] =self.total_page
                l.append('<li ><a href="{}?{}">尾页</a></li>'.format(self.current_url,self.request_params.urlencode()))
            return l                       
    

    分类功能

    通过以下方法可以拿到外键表中所有的实例化对象

    Article._meta.get_field(field_name).remote_field.model.objects.all()
    # 通过他可以拿到外键表所有实例化对象
    

    实验说明

    class A():
        pass
    a=A()
    print(type(a))
    --------------------------------------
    结果是:
        <class '__main__.A'>   # 当前文件下,A类实例化的对象
        
    
    
    
    
    filter_list=["user","tags","category"]
    def get_filter_html(self):
        catage_list = self.config.filter_list
        for field in catage_list:  # 拿到分类字段,即组合依据
            data_list=self.config.model._meta.get_field(field).remote_field.model.objects.all()
                # 获取字段对象并反射获取外键表某字段的全部返回值
            for obj in data_list:
                print(type(obj))
    ------------------------------------------
    结果是:
        <class 'app01.models.UserInfo'>
        <class 'app01.models.UserInfo'>
        <class 'app01.models.UserInfo'>
        <class 'app01.models.UserInfo'>
        <class 'app01.models.UserInfo'>
        <class 'app01.models.Tag'>
        <class 'app01.models.Tag'>
        <class 'app01.models.Tag'>
        <class 'app01.models.Category'>
        <class 'app01.models.Category'>
        <class 'app01.models.Category'>
        <class 'app01.models.Category'>
        <class 'app01.models.Category'>
    拿到的是类对应实例化对象
    
    models.Article._meta.get_field("tags").remote_field.model.objects.all()
    
    ---------------------------------------
    结果是
        <QuerySet [<Tag: 游戏>, <Tag: 生活>, <Tag: 情感>]>
    

    getattr拿到的是反射对象中__ str__定义的返回值,因为该方法获取到的是外键表所有实例化的对象,因此才会返回__ str__数据

     def __str__(self):
            return self.title
    

    注意当有两个参数时,for循环取值,只会拿到最后一个值,需要分别用getlist取值

     print(request.GET)
     for k,v in request.GET.items():
       print(k)
       print(type(v),v)
       
    ----------------------------------------   
    结果是:
        <QueryDict: {'user': ['12'], 'tags': ['1', '2']}>
        user
        <class 'str'> 12
        tags
        <class 'str'> 2
    
  • 相关阅读:
    由基于qml,c++的串口调试工具浅谈qml与c++混合编程
    qt5_qml_Opengl_shader 第一弹----------------------openglunderqml的简化及介绍
    Delphi 的接口机制——接口操作的编译器实现过程(2)
    Delphi 的接口机制——接口操作的编译器实现过程(1)
    ddd
    [leetcode]Gray Code
    synapse socket总结一:服务器模型
    CentOS 6.5(64bit)安装GCC4.8.2+Qt5.2.1(替换GCC的链接库)
    Qt打开外部程序和文件夹需要注意的细节(Qt调用VC写的动态库,VC需要用C的方式输出函数,否则MinGW32编译过程会报错)
    Qt+SQLite数据加密的一种思路(内存数据库)
  • 原文地址:https://www.cnblogs.com/AbnerLc/p/11203876.html
Copyright © 2020-2023  润新知