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. 事务:数据的原子性、隔离性、持久性、一致性

 

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)

猜你喜欢

转载自www.cnblogs.com/zhangyaqian/p/py20180622.html
今日推荐