Django ORM那些相关操作

  • A+
所属分类:Python教程 学编程

一、一般操作

官方文档

1.1、基础查询必会十三条

1.通过以下方法获取到的结果为QuerySet对象

models.Person.object.all()           #获取Person表下的所有信息
models.Person.object.filter(id=1)           #获取Person表下id等于1的值,获取到的数据时QuerySet对象,需要使用下标获取具体的内容,如果数据库里没有该数据时使用filter方法时不会报错,指挥返回空的QuerySet对象。
models.Person.object.exclude(id=1)      #获取除了id是1之外的所有值,如果是不存在的就把所有的值都获取
models.Person.object.all().order_by('age')         #对查询结果进行根据age字段排序
models.Person.object.order_by('age').reverse()            #对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
models.Person.object.all().distinct()          #从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

2.通过以下方法获取到的结果为特殊的QuerySet

models.Person.object.values("name","birthday")         #获取Person表里name、birthday的字段和字段对应的值,如果不指定获取的字段默认全部获取(values返回一个QuerySet对象,里面都是字典)
models.Person.object.values_list("name","birthday")         #它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

3.通过以下方法获取到的结果为具体的对象

models.Person.object.get(id=1)           #获取Person表下id等于1的值,直接获取到对应的值,但是如果数据库里没有该数据时使用get方法会报错。
models.Person.object.all().first()              返回第一条记录
models.Person.object.all().last()               返回最后一条记录

4.通过以下方法获取到的结果为布尔值

models.Person.object.exists()             如果QuerySet包含数据,就返回True,否则返回False

5.通过以下方法获取数据的总条数

models.Person.object.all().count()              #返回数据库中匹配查询的数据总数

1.2、单表查询之双下划线方法

ret1 = models.Person.objects.filter(id__gt=1,id__lt=5)        #获取id大于1 and id小于5的值

ret2 = models.Person.objects.filter(id__in=[2,4,5])           #获取id是2,4,5的值

ret3 = models.Person.objects.exclude(id__in=[2,4,5])          #exclude取反所以是not in(即获取id不是2,4,5的数据)

ret4 = models.Person.objects.filter(name__contains="四")      #获取name字段包含“四”的值

ret5 = models.Person.objects.filter(name__icontains="test")      #icontains:大小写不敏感

ret6 = models.Person.objects.filter(id__range=[1, 3])         #获取的ID范围是1-3的数据,相当于sql的bettwen and

ret7 = models.Person.objects.filter(birthday__year=2019)       #时间格式的查询可以指定查询指定的年份或者月份

ret8 = models.Person.objects.filter(birthday__year=2007,birthday__month=5)       #时间格式的查询可以指定查询指定的年份或者月份

ret9 = models.Person.objects.filter(title__startswith="中关村")        #获取title的值为以中关村开头的

ret10 = models.Person.objects.filter(title__endswith="中关村")        #获取title的值为以中关村结尾的

二、外键操作(ForeignKey)

跨表查询分为正向查找和反向查找,那么什么是正向查找?什么是反响查找?

  • 正向查找:从有外键字段的表查询关联的表叫正向查找。
  • 反向查找:从关联表查询有外间字段的表叫反向查找。

    2.1、正向查找

    1.对象查找(跨表)

book_obj = models.Book.objects.first()       #获取第一本书对象
print(book_obj.publisher)         #获取第一本书对应的出版社对象
print(book_obj.publisher.name)       #获取第一本书对应出版社对应的名字

2.字段查找
通过双下划线跨表查找(双下划线就表示跨了一张表)

ret = models.Book.objects.filter(id=1).values("publisher__name")

2.2、反向查找

1.基于对象的跨表查找

publisher_obj = models.Publisher.objects.first()     # 找到第一个出版社对象
print(publisher_obj)

#默认查找是表名+_set的方式查找
# print(publisher_obj.book_set.all())       # 找到第一个出版社出版的所有书(建表的语句里没有related_name="books",的查询方法)

#如果建表的语句里有related_name="books",的查询方法如下
print(publisher_obj.books.all())       # 找到第一个出版社出版的所有书(建表的语句里有related_name="books",的查询方法)
# print(publisher_obj.book_set.all().values_list("title"))      # 找到第一个出版社出版的所有书的书名
print(publisher_obj.books.all().values_list("title"))      # 找到第一个出版社出版的所有书的书名

说明:publisher_obj.book_set.all()和publisher_obj.books.all()两种查询方法只能用一种(那种方便用那种)
2.基于双下划线的跨表查询

titles1 = models.Publisher.objects.values_list("book__title")        #查找出版社对应的书(建表语句里没有指定related_name="books",时的查询方法)

titles1 = models.Publisher.objects.values_list("books__title")        #查找出版社对应的书(建表语句里指定了related_name="books",时的查询方法)

titles1 = models.Publisher.objects.values_list("xxoo__title")        #查找出版社对应的书(建表语句里指定了related_query_name="xxoo",时的查询方法)

说明:

  • 建议使用上边的查询方法:
titles1 = models.Publisher.objects.values_list("books__title")
  • 使用.get()方法获取到的是一个具体的对象,该对象有什么属性就通过.属性来获取,例如:publisher.name(获取name属性的字段)

  • 使用.filter()方法获取到的是QuerySet对象,使用.filter()得到的QuerySet对象才可以使用.values()方法和.values_list()方法。

三、多对多(ManyToManyField)

3.1、查询第一个作者的名字

author_obj = models.Author.objects.first()
print(author_obj.name)

3.2、查询第一个作者写过的书

ret = author_obj.books.all()
print(ret)

3.3、方法之create

通过作者创建一本书,会自动保存(第一步:在book表里创建一本新书。第二步:在作者和书的关系表中添加关联记录)

# author_obj.books.create(title="运维那些年",publisher_id=2)

5.4、方法之add

将一本书与某一作者添加关系

book_obj = models.Book.objects.get(id=4)       #获取到书
author_obj.books.add(book_obj)         #通过add将刚查到的书与作者添加关联
author_obj.books.add(8)         #直接通过书对应的id将书添加到作者关联

3.5、将多本书与某一作者添加关系

book_objs = models.Book.objects.filter(id__lt=4)       #获取到id小于4的书
author_obj.books.add(*book_objs)         #通过add将刚查到的书与作者添加关联(要把列表打散再传进去)

3.6、方法之set

更新关联的对象

book_obj = models.Book.objects.first()        #获取第一本书
book_obj.authors.set([2, 3])        #通过书设置关联的作者(id)

3.7、方法之remove

将张三丰关联的书中将从删库到跑路删除掉

book_obj = models.Book.objects.get(title="从删库到跑路")       #获取到书籍信息
author_obj.books.remove(book_obj)         #从作者的关联的book信息里删除刚查找到的书

3.8、方法之clear(清空)

将id是2的作者关联的书全部删掉

er_obj = models.Author.objects.get(id=2)      #获取到id是2的作者
er_obj.books.clear()       #清空id是2作者的全部书籍

3.9、补充:

  • 当外键没有设置可以为空(null=True)时,不可以使用clear()和remove()方法。
    示例:
publisher_obj = models.Publisher.objects.get(id=1)        #获取publisher表里id是1的值
publisher_obj.books.clear()         #将id是1的出版社关联的书清空(如果外键没有设置可以为空,执行这步时会报错)

四、聚合查询和分组查询

4.1、聚合查询

from django.db.models import Avg,Sum,Max,Min,Count       #导入模块:1.Avg:平均值。2.Sum:合。3.Max:最大值。4.Min:最小值。5.Count:计数
ret = models.Book.objects.all().aggregate(price__avg=Avg("price"))       #求平均值,结果为:{'price__avg': 99.99}
print(ret)
ret = models.Book.objects.all().aggregate(price__avg=Avg("price"), price__max=Max("price"), price__min=Min("price"), price__sum=Sum("price"))      #可以进行多个聚合,结果为:{'price__avg': 99.99, 'price__max': Decimal('99.99'), 'price__min': Decimal('99.99'), 'price__sum': Decimal('599.94')}
print(ret.get('price__max'))        #获取最大值,结果为:99.99

4.2、分组查询

1.统计一本书的作者数量

from django.db.models import Count,Sum
ret = models.Book.objects.all().annotate(author_num=Count("author"))
for book in ret:
    print("书名:",book," - ","作者数量:",book.author_num)

2.查询作者数量大于1的书

ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1)
print(ret)

3.求作者出书的总价格

  • 方法一
ret = models.Author.objects.all().annotate(price_sum=Sum('books__price')).values_list('name','price_sum')
print(ret)
  • 方法二
ret = models.Author.objects.all().annotate(price_sum=Sum('books__price'))
print(ret)
print(ret.values_list("id","name","price_sum"))
for i in ret:
    print(i,i.name,i.price_sum) 

4.求分组平均工资
1.原生SQL如下:

select dept,AVG(salary) from employee group by dept;

2.对应的ORM如下

from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")

3.联标查询如下

1.原生SQL如下
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;

2.ORM查询如下
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

五、F查询和Q查询

1、当需要字段和字段作比较的时候用F查询
2、当查询条件是 或 的时候用Q查询,因为默认的filter参数都是且的关系

5.1、F查询

1.查出库存数 大于 卖出数 的所有书

from django.db.models import F
ret = models.Book.objects.filter(kucun__gt=F("maichu"))      #1.F("maichu"):会查询出maichu字段对应的值。2.然后通过kucun的__gt方法进行对比
print(ret)

2.将每一本数的卖出数都乘以三

models.Book.objects.update(maichu=F("maichu") * 3)        #这样写如果卖出数是0的*3还是0
models.Book.objects.update(maichu=(F("maichu")+1) * 3)        #这样写就不会有0*3还是0的情况

3.修改字符串,将书名后面加上:第一版

from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F("title"),  Value("第一版")))      #修改title的值为:title+第一版

5.2、Q查询

1.查询卖出数大于一千 或者 价格小于五十的所有书

from django.db.models import Q
ret = models.Book.objects.filter(Q(maichu__gt=1000)|Q(price__lt=50))
print(ret)

补充:

  • Q查询和字段查询同时使用时
    如果一个查询语句里同时包含Q查询和字段查询时,字段查询要放在Q查询的后面(字段查询放在Q的前面时会报错)
ret = models.Book.objects.filter(Q(maichu__gt=1000)|Q(price__lt=50),title__contains="运维那点事")       #title__contains="关键字"  要放在Q查询的后面
print(ret)

六、一对一(OneToOneField)

  • 当一张表的某一些字段查询的比较频繁,另外一些字段的查询不是特别频繁
  • 把不怎么常用的字段 单独拿出来做成一张表 然后用一对一关联起来

    6.1、一对一使用

class l(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    info = models.OneToOneField(to="l_info")        #字段名 = models.OneToOneField(to="关联的表"),info_id字段限制不可以重复

class l_info(models.Model):
    hobby = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

6.2、一对一的查询

1_obj = models.L.object.get(id=1)
obj = l_obj.info
print(obj.hobby,obj.addr)

七、Django终端打印原生SQL配置

在Django项目的settings.py文件中,在最后粘贴如下代码:

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

即为你的Django项目配置上一个名为django.db.backends的logger实例即可查看翻译后的SQL语句。

八、在一个单独的Python脚本中调用Django环境

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")       #这个配置
    import django     #导入django
    django.setup()    #启动django

    from app01 import models      #引用django里的方法

    books = models.Book.objects.all()
    print(books)

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: