zoukankan      html  css  js  c++  java
  • Django(二)

    QuerySet与惰性机制:

    所谓惰性机制:Publisher.objects.all()或者所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。

    QuerySet特点:

    • (1)可迭代的

    • (2)可切片

        #objs=models.Book.objects.all()#[obj1,obj2,ob3...]
        
            #QuerySet:   可迭代
        
            # for obj in objs:#每一obj就是一个行对象
            #     print("obj:",obj)
            # QuerySet:  可切片
        
            # print(objs[1])
            # print(objs[1:4])
            # print(objs[::-1])
      

    QuerySet的高效使用:

    	<1>Django的queryset是惰性的
    	
    	     Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得
    	     到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
    	     上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
    	     这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。
    	
    	<2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
    	   为了验证这些,需要在settings里加入 LOGGING(验证方式)
    	        obj=models.Book.objects.filter(id=3)
    	        # for i in obj:
    	        #     print(i)
    	
    	        # if obj:
    	        #     print("ok")
    	
    	<3>queryset是具有cache的
    	     当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行
    	    (evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,
    	     你不需要重复运行通用的查询。
    	        obj=models.Book.objects.filter(id=3)
    	
    	        # for i in obj:
    	        #     print(i)
    	                          ## models.Book.objects.filter(id=3).update(title="GO")
    	                          ## obj_new=models.Book.objects.filter(id=3)
    	        # for i in obj:
    	        #     print(i)   #LOGGING只会打印一次
    	
    	<4>
    	     简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些
    	     数据!为了避免这个,可以用exists()方法来检查是否有数据:
    	
    	            obj = Book.objects.filter(id=4)
    	            #  exists()的检查可以避免数据放入queryset的cache。
    	            if obj.exists():
    	                print("hello world!")
    	
    	<5>当queryset非常巨大时,cache会成为问题
    	
    	     处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统
    	     进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法
    	     来获取数据,处理完数据就将其丢弃。
    	        objs = Book.objects.all().iterator()
    	        # iterator()可以一次只从数据库获取少量数据,这样可以节省内存
    	        for obj in objs:
    	            print(obj.name)
    	        #BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
    	        for obj in objs:
    	            print(obj.name)
    	
    	     #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使
    	     #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询
    	
    	总结:
    	    queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
    	使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
    	会造成额外的数据库查询。
    

    这里需要了解的是Django的日志功能:

    下面是我的自己常用到的日志文件,ORM封装好的sql语句对应的执行过程都会在编译器显示,需要在settings加上日志记录部分:

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }
    

    对象查询,单表条件查询,多表条件关联查询

    #--------------------对象形式的查找--------------------------
        # 正向查找
        ret1=models.Book.objects.first()
        print(ret1.title)
        print(ret1.price)
        print(ret1.publisher)
        print(ret1.publisher.name)  #因为一对多的关系所以ret1.publisher是一个对象,而不是一个queryset集合
    
        # 反向查找
        ret2=models.Publish.objects.last()
        print(ret2.name)
        print(ret2.city)
        #如何拿到与它绑定的Book对象呢?
        print(ret2.book_set.all()) #ret2.book_set是一个queryset集合
    
    #---------------了不起的双下划线(__)之单表条件查询----------------
    
    #    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    #
    #    models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
    #    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    #
    #    models.Tb1.objects.filter(name__contains="ven")
    #    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    #
    #    models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    #
    #    startswith,istartswith, endswith, iendswith,
    
    #----------------了不起的双下划线(__)之多表条件关联查询---------------
    
    # 正向查找(条件)
    
    #     ret3=models.Book.objects.filter(title='Python').values('id')
    #     print(ret3)#[{'id': 1}]
    
          #正向查找(条件)之一对多
    
          ret4=models.Book.objects.filter(title='Python').values('publisher__city')
          print(ret4)  #[{'publisher__city': '北京'}]
    
          #正向查找(条件)之多对多
          ret5=models.Book.objects.filter(title='Python').values('author__name')
          print(ret5)
          ret6=models.Book.objects.filter(author__name="alex").values('title')
          print(ret6)
    
          #注意
          #正向查找的publisher__city或者author__name中的publisher,author是book表中绑定的字段
          #一对多和多对多在这里用法没区别
    
    # 反向查找(条件)
    
        #反向查找之一对多:
        ret8=models.Publisher.objects.filter(book__title='Python').values('name')
        print(ret8)#[{'name': '人大出版社'}]  注意,book__title中的book就是Publisher的关联表名
    
        ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
        print(ret9)#[{'book__authors': 1}, {'book__authors': 2}]
    
        #反向查找之多对多:
        ret10=models.Author.objects.filter(book__title='Python').values('name')
        print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
    
        #注意
        #正向查找的book__title中的book是表名Book
        #一对多和多对多在这里用法没区别
    

    注意:条件查询即与对象查询对应,是指在filter,values等方法中的通过__来明确查询条件。

    聚合查询和分组查询

    (1) aggregate(*args,**kwargs):

    通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
    
    from django.db.models import Avg,Min,Sum,Max
    
    从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有
    图书的集合。
    
    >>> Book.objects.all().aggregate(Avg('price'))
    {'price__avg': 34.35}
    
    aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值
    
    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的
    标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定
    一个名称,可以向聚合子句提供它:
    >>> Book.objects.aggregate(average_price=Avg('price'))
    {'average_price': 34.35}
    
    
    如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
    >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
    {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
    

    (2) annotate(*args, **kwargs):

    可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

    1.查询某个作者出的书的总价格

    2.查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是authors__name


    3.查询各个出版社最便宜的书价是多少

    F查询和Q查询

    仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:

    # F 使用查询条件的值,专门取对象中某列值的操作
    
        # from django.db.models import F
        # models.Tb1.objects.update(num=F('num')+1)
    
    
    # Q 构建搜索条件
        from django.db.models import Q
    
        #1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
        q1=models.Book.objects.filter(Q(title__startswith='P')).all()
        print(q1)#[<Book: Python>, <Book: Perl>]
    
        # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
        Q(title__startswith='P') | Q(title__startswith='J')
    
        # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
        Q(title__startswith='P') | ~Q(pub_date__year=2005)
    
        # 4、应用范围:
    
        # Each lookup function that takes keyword-arguments (e.g. filter(),
        #  exclude(), get()) can also be passed one or more Q objects as
        # positional (not-named) arguments. If you provide multiple Q object
        # arguments to a lookup function, the arguments will be “AND”ed
        # together. For example:
    
        Book.objects.get(
            Q(title__startswith='P'),
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
        )
    
        #sql:
        # SELECT * from polls WHERE question LIKE 'P%'
        #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
    
        # import datetime
        # e=datetime.date(2005,5,6)  #2005-05-06
    
        # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
        # 正确:
        Book.objects.get(
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
            title__startswith='P')
        # 错误:
        Book.objects.get(
            question__startswith='P',
            Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
    

    admin的配置

    admin是django强大功能之一,它能够从数据库中读取数据,呈现在页面中,进行管理。默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经够用,但是有时候,一些特殊的功能还需要定制,比如搜索功能,下面这一系列文章就逐步深入介绍如何定制适合自己的admin应用。

    如果你觉得英文界面不好用,可以在setting.py 文件中修改以下选项

    LANGUAGE_CODE = 'en-us'  #LANGUAGE_CODE = 'zh-hans'
    

    一 认识ModelAdmin

    管理界面的定制类,如需扩展特定的model界面需从该类继承。

    二 注册medel类到admin的两种方式

    <1> 使用register的方法

    admin.site.register(Book,MyAdmin)
    

    <2> 使用register的装饰器

    @admin.register(Book)
    

    三 掌握一些常用的设置技巧

    • list_display: 指定要显示的字段

    • search_fields: 指定搜索的字段

    • list_filter: 指定列表过滤器

    • ordering: 指定排序字段

        from django.contrib import admin
        from app01.models import *
        # Register your models here.
        
        # @admin.register(Book)#----->单给某个表加一个定制
        class MyAdmin(admin.ModelAdmin):
            list_display = ("title","price","publisher")
            search_fields = ("title","publisher")
            list_filter = ("publisher",)
            ordering = ("price",)
            fieldsets =[
                (None,               {'fields': ['title']}),
                ('price information', {'fields': ['price',"publisher"], 'classes': ['collapse']}),
            ]
        
        admin.site.register(Book,MyAdmin)
        admin.site.register(Publish)
        admin.site.register(Author)
  • 相关阅读:
    3.List.Set
    2.Collection.泛型
    1.Object类.常用API
    MySQL-核心技术
    奇异的家族-动态规划
    动态规划-等和的分隔子集
    跳跃游戏-贪心
    跳跃游戏2
    爬楼梯
    组合博弈1536-S-Nim
  • 原文地址:https://www.cnblogs.com/lijian-22huxiaoshan/p/7445439.html
Copyright © 2011-2022 走看看