• 22 Jun 18 Django,ORM


    22 Jun 18

    一、F查询

    0. 字段和常量间作比较;如果不使用F函数,想比较两个字段相对麻烦。

       models.Product.objects.filter(maichu_gt=10)

     

    1. 两个字段之间作比较(F查询应用一)

        models.Product.objects.filter(maichu__gt=F("kucun"))

     

    2. Django支持F()对象之间以及F()对象和常数之间的加减乘除和取模的操作。

       a. 使用F函数进行查找操作

       models.Product.objects.filter(maichu_lt=F('kucun')*2)

     

       b. 使用F函数进行修改操作

       models.Book.objects.all().update(price=F('price')+30)

     

    3. 字符串拼接 (F查询应用二)

        from django.db.models.functions import Concat

        from django.db.models import Value

        # 在Product表中name字段的每个值后拼接'新款'

        models.Product.objects.update(name=Concat(F("name"), Values("("), Value("新款"), Value(")")))

        # update:更新数据, 只能接在QuerySet对象后;F(要拼接的字段名);Value(要拼接的内容)

     

    二、update修改字段和对象.属性修改字段的区别

    1. 对象.属性方法会更新所有字段; update方法只会更新修改的那个字段

       # 用update放大效率更高,推荐

    2. 对象.属性方法需要后跟obj.save();update方法不需要save

    3. 对象.属性方法只能应用于对象;update方法只能应用于QuerySet对象

     

    # 使用对象.属性修改字段

    publisher_obj = models.Publisher.objects.first()  # 得到一个对象,为后续操作提供条件

    publisher_obj.name = "沙河出版社"

    publisher_obj.save()  # 对象.属性修改字段后需要.save()保存修改

     

    # 使用update方法修改字段 (应用于QuerySet对象)

    models.Publisher.objects.filter(id=1).update(name="北京沙河出版社")

     

    三、Q查询

    filter() 等方法中的关键字参数查询都是取并集操作的。 如果需要执行更复杂的查询(例如OR语句),可以使用Q对象。

    #1 多个查询条件做 交集 并集 取反 操作时

    #2 如果Q查询和关键字查询同时存在时,Q查询要放在关键字查询的前面!

     

    0. 查询卖出数大于100 并且 价格小于100块的:多个条件做交集可使用关键字参数查询

      models.Product.objects.filter(maichu__gt=100, price__lt=100)

     

    1. 查询 卖出数大于100 或者 价格小于100块的

       from django.db.models import Q

      print(models.Product.objects.filter(Q(maichu__gt=100)|Q(price__lt=100)))

       # |: 或

     

    2. 查询 库存数是100 并且 卖出数不是0 的产品

       print (models.Product.objects.filter(Q(kucun=100) & ~Q(maichu=0)))

       # &: 并且;~: 非

     

    3. 查询产品名包含新款, 并且库存数大于60的 (查询函数可以混合使用Q 对象和关键字参数)

       print (models.Product.objects.filter(Q(kucun__gt=60), name__contains="新款"))

       print (models.Product.objects.filter(kucun__gt=60, name__contains="新款"))

       print (models.Product.objects.filter(name__contains="新款",Q(kucun__gt=60))  # 报错positional argument follows keyword argument

     

    四、事务

    1. 数据库事务必须具备ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔离性,Durability持久性。

     

    2. Django ORM事务

        from django.db.models import F

        from django.db import transaction

     

        # 开启事务处理

        try:

            with transaction.atomic():

                # 创建一条订单数据

               models.Order.objects.create(num="110110111", product_id=1, count=1)

                # 报错,get()得到的是一个对象,无法使用update方法

                # models.Product.objects.get(id=1).update(kucun=F("kucun")-1, maichu=F("maichu")+1)

                # 去产品表 将卖出数+1, 库存数-1 (可正常执行语句)

               models.Product.objects.filter(id=1).update(kucun=F("kucun")-1, maichu=F("maichu")+1)

        except Exception as e:

            print(e)

     

        # 不开启事务 (第一条语句执行成功,数据库已完成修改,但第二条语句执行失败并报错)

        try:

           models.Order.objects.create(num="110110110", product_id=1, count=1)

           models.Product.objects.get(id=1).update(kucun=F("kucun") - 1, maichu=F("maichu") + 1)

        except Exception as e:

            print(e)

     

    五、其他:select_related和prefetch_related

    1. select_related

       性能相关:表之间进行join连表操作,一次性获取关联的数据,以减少查询数据库的次数; 适用于一对一和多对一的查询的情况

     

       # 操作一个对象

      print(models.B.objects.first().a.name)

     

       # 操作多个对象,不使用select_related

       b_list = models.B.objects.all()

       for b in b_list:

           print(b.a.name)

     

       # 操作多个对象,使用select_related

       b_list = models.B.objects.select_related("a").all()

       for b in b_list:

           print(b.a.name)

     

    2. prefetch_related 利用Python 来做类似JOIN操作

       性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。

     

       # 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。

       # prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。

     

    六、bulk_create

    import random

    data = ["".join([str(random.randint(65, 99)) for i in range(4)]) for j in range(100)]

     

    # 不使用批量操作

    for i in data:

       models.A.objects.create(name=i)

     

    # 使用批量操作bulk_create

    obj_list = [models.A(name=i) for i in data]

    models.A.objects.bulk_create(obj_list)

     

    random及列表推导式复习:

    # 产生100个8位数字随机数

    import random

    # 不使用列表生成式

    ret = []

    for j in range(100):

        list1 = []

        for i in range(4):

            list1.append(str(random.randint(65, 99)))  # ['82', '74', '73', '93']

            # 必须转换成字符串先,后续才能有,连接

       ret.append("".join(list1))

    print(ret)  # ["66676869", "69656863", ...]

     

    # 列表生成式

    ret2 = [ "".join([str(random.randint(65, 99)) for i in range(4)]) for j in range(100)]

    print(ret2)  # ["66676869", "69656863", ...]

     

    七、ORM执行原生SQL的方法

    1. extra

        # 查询书籍名称和出版时间(年月)

       print(models.Book.objects.all().extra(select={"z": "DATE_FORMAT(publish_date, '%%Y-%%m')"}).values("title", "z"))

        

        # 将 书籍 按 年月 归档(BBS项目后续会使用)

        from django.db.models import Count

        print(models.Book.objects.extra(select={"z": "DATE_FORMAT(publish_date, '%%Y-%%m')"}).values("z").annotate(num=Count("id")).values("z", "num"))

     

    2. 类似pymysql方式(更灵活的执行原生SQL语句)

        from django.db import connection

        cursor = connection.cursor()  # cursor = connections['default'].cursor()

        cursor.execute("""SELECT * from app01_book where id = %s""", [1])

        row = cursor.fetchone()

        print(row)

  • 相关阅读:
    Java文件流应用:复制文件
    Java IO流之文件流
    初识Java-IO流
    Java集合之Properties
    Java之FilenameFilter接口
    Java之File类
    Java内部类
    Java常用类之要点总结
    Java异常类(Throwable)
    php分布式缓存系统 Memcached 入门
  • 原文地址:https://www.cnblogs.com/zhangyaqian/p/py20180622.html
Copyright © 2020-2023  润新知