ORM增删改查

#一、ORM单表的增删改查

    #表记录的添加
        from app1.models import *
        #方式1
        Author.objexts.create(name='alvin')
        #方式2
        Author.objects.create(**{'name':'alex'})
        
     #方式1
        author = Author(name='alvin')
        author.save()
        #方式2
        author = Author()
        author.name = 'alvin'
        author.save()

    #表记录的修改
        #方式1
            Book.object.filter(author='kang').update(price=100)
        #方式2(有save的效率低,不建议用)
            b = Book.objects.get(author='kang')
            b.price = 123
            b.save()
    #表记录的删除
        Book.objects.filter(author='kang').delete()

    #表记录的查找

        #相关查询API
        filter(**kwargs)   包含了与所给筛选条件相匹配的对象,按照条件选出结果
        all()   查询所有结果
        get(**kwargs)    返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会报错

        #下面的方法都是对查询的结果进行处理
        values(*field)    返回一个字典序列
        exclude(**kwargs)  包含了与所给筛选条件不匹配的对象,按照条件排除结果
        order_by(*field)   对查询结果进行排序
        reverse()   对查询结果反向排序
        distinct()   从返回结果中剔除重复记录
        values_list(*field)  返回的是一个元组序列,values返回的是一个字典序列
        count()   返回数据库中匹配查询(QuerySet)的对象数量
        first()  返回第一条记录
        last()  返回最后一条记录
        exists()   如果QuerySet包含数据,则返回True,否则返回False

        __gt大于
        __lt小于
        __in 等于
        __contains 按大写选择
        __icontains 不区分大小写
        __range  在什么之间

# django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常:
# TypeError: init() missing 1 required positional argument: ‘on_delete’
#
# on_delete各个参数的含义如下:
#
#     on_delete=None,               # 删除关联表中的数据时,当前表与其关联的field的行为
#     on_delete=models.CASCADE,     # 删除关联数据,与之关联也删除
#     on_delete=models.DO_NOTHING,  # 删除关联数据,什么也不做
#     on_delete=models.PROTECT,     # 删除关联数据,引发错误ProtectedError
#     # models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
#     on_delete=models.SET_NULL,    # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
#     # models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
#     on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
#     on_delete=models.SET,         # 删除关联数据,
#      a. 与之关联的值设置为指定值,设置:models.SET(值)
#      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
#
# 由于多对多(ManyToManyField)没有 on_delete 参数,所以以上只针对外键(ForeignKey)和一对一(OneToOneField)


#二、ORM多表的增删改查

# ORM多表1(一对多)

    # 添加
        Book.objects.create(name='python',price=34,pub_date='2021-01-01',publish_id=2)
        Book.objects.create(name='java',price=10,pub_date='2019-08-01',publish_id=3)

    # 修改
        Book.objects.filter(id=17).update(price=100,pub_date='1998-11-13')

    # 删除
        Book.objects.filter(name='php').delete()   #删除名字为PHP的书

    # 查询:
        # 实例1:查询人民出版社出过的所有书籍的名字和价格
            # 方式1
            pub_obj = Publish.objects.filter(name='人民出版社')[0]
            ret = Book.objects.filter(publish=pub_obj).values('name','price')
            print(ret)

            # 方式2
            pub_obj = Publish.objects.filter(name='人民出版社')[0]
            ret = pub_obj.book_set.all().values('name','price')
            print(ret)

            # 方式3(通过双下划线)
            ret = Book.objects.filter(publish__name='人民出版社').values('name','price')
            print(ret)

        # 实例2:查询python这本书出版社的名字
            # 方式1
            ret0 = Publish.objects.filter(book__name='python').values('name')
            print(ret0)

            # 方式2
            ret1 = Book.objects.filter(name='python').values('publish__name')
            print(ret1)

        # 实例3:通过对象来查找记录
            book_obj = Book.objects.get(name='python')
            print(book_obj)   #python
            print(book_obj.name)  #name=python
            print(book_obj.price)  #price=34
            print(book_obj.pub_date)   #pub_date=2021-01-01
            print(book_obj.publish)   #Publish object
            print(book_obj.publish.name)    #机械出版社
            print(book_obj.publish.city)  #上海
            print(book_obj.publish.id)  #2
            print(book_obj.publish_id)  #publish_id=2
            print(book_obj.id)    #id=13

        # 实例4:查询生产地在甘肃兰州的书的名字
            ret = Book.objects.filter(publish__city='甘肃兰州').values('name')
            print(ret)   #go和java

        # 实例5:查找生产时间在2010-01-01到2021-07-29之间出版的书
            ret = Book.objects.filter(pub_date__lt='2021-07-29',pub_date__gt='2010-01-01').values('name')  #__lt小于,__gt大于
            print(ret)  #python/linux/go/HTML/java

        # 实例6:查找java的出版社
            # 方式1
            ret = Publish.objects.filter(book__name='java').values('name')
            print(ret)    #甘肃出版社

            # 方式2
            ret = Book.objects.filter(name='java').values('publish__name')
            print(ret)

# ORM多表2(多对多)

    #增加
        # 创建多对多的关系:author = models.ManyToManyField("Author")------>此时会自动生成关联表
        #(1)book_authors表添加信息
            #添加一条信息
                book_obj = Book.objects.get(id=13)   #书的对象
                author_objs = Author.objects.get(id=1)
                book_obj.authors.add(author_objs)
            #添加多条信息
                book_obj = Book.objects.get(id=19)
                author_objs = Author.objects.all()
                book_obj.authors.add(*author_objs)

        #(2)通过创建第三张表来添加信息
            Book_Author.objects.create(book_id=16,author_id=1)

    #修改
        修改与一对多修改方式一样

    #删除
        #对book_authors表删除信息(即删除自动生成表的信息)
            #删除一条信息
                book_obj = Book.objects.get(id=19)
                author_objs = Author.objects.get(id=1)
                book_obj.authors.remove(author_objs)
            #删除多条信息
                book_obj = Book.objects.get(id=19)
                author_objs = Author.objects.all()
                book_obj.authors.remove(*author_objs)

    #查询
        #(一)、通过对象的方式绑定关系(自动生成的第三张表的操作)
        #方式1
            book_obj = Book.objects.get(id=13)            
       print(book_obj.authors.all())  #QuerySet对象
       print(type(book_obj.authors.all()))  #<class 'django.db.models.query.QuerySet'>

        #方式2
            author_obj = Author.objects.get(id=2)            
       print(author_obj.book_set.all())        

    #(二)、通过创建的第三张表来查找
  
    #alex出过的书籍名称及价格
            ret = Book.objects.filter(book_author__author__name='alex').values('name','price')            
       print(ret)        

#注:以下实例都使用自动生成的第三张表来操作
    #实例1:查找alex出过的书籍的名字及价格
            ret_0 = Book.objects.filter(authors__name='alex').values('name','price')            
       print(ret_0)  #<QuerySet [{'name': 'HTML', 'price': 540}, {'name': 'java', 'price': 10}, {'name': 'python', 'price': 34}]>

        #聚合函数:
                annotate(*args,**kwargs):可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。
                aggregate(*args,**kwargs):通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。
        #实例2:求price的平均值
                  ret_1 = Book.objects.all().aggregate(Avg('price'))                    
             print(ret_1)                

        #实例3:求price的总和
                    ret_2 = Book.objects.all().aggregate(Sum('price'))                    
            print(ret_2)                

        #实例4:求price的最小值
                    ret_3 = Book.objects.all().aggregate(Min('price'))                    
            print(ret_3)  #{'price__min': 20}

             #实例5:求price的最大值
                    ret_4 = Book.objects.all().aggregate(max_money=Max('price'))                    
            print(ret_4)   #{'max_money': 550}------>max_mongy是可以自己定义的

        #实例6:alex出过书的总价格
                   ret_5 = Book.objects.filter(authors__name='alex').aggregate(Sum('price'))                    
            print(ret_5)                

        #实例7:alex出过书的数量
                    ret_6 = Book.objects.filter(authors__name='alex').aggregate(Count('name'))                    
            print(ret_6)        

    #分组
        #实例8:求每个作者出过书的总价格
                ret_7 = Book.objects.values('authors__name').annotate(Sum('price'))                
         print(ret_7)        

    #F查询:使用查询条件的值进行操作
        #实例9:为每本书增加10块钱
                Book.objects.all().update(price=F('price')+10)        

    #Q查询:
        #实例10:找价格为44或者名字为go的
                ret_8 = Book.objects.filter(Q(price=44) | Q(name='go'))                
          print(ret)            

        #实例11:查找书名中有P的书
                ret_9 = Book.objects.filter(Q(name__contains='p'))                
         print(ret_9)            
  
        #实例12:查找书名中有l的并且价格为53的书
                ret_10 = Book.objects.filter(Q(name__contains='l') & Q(price=53))                
         print(ret_10)   #linux

            #~(非)的使用
                ret_11 = Book.objects.filter(Q(name__contains='l')& ~ Q(price=53))                
          print(ret_11)  #linux运维

注:
Djangoqueryset的惰性机制
# <1>Djangoqueryset是惰性的
#
# Djangoqueryset对应于数据库的若干记录(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时,所有匹配的记录会从数据库获取,然后转换成Djangomodel。这被称为执行
# 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()的检查可以避免数据放入querysetcache
# 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时没有重复执行查询
#
# 总结:
# querysetcache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
# 使用exists()iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
# 会造成额外的数据库查询。
 

 

posted @ 2021-07-31 20:19  ShadowFolk  阅读(137)  评论(0编辑  收藏  举报