ORM查询操作

ORM查询操作

1、如何只单独测试Django中的某一个py文件

在应用下的tests文件或者新建任意一个py文件中书写以下代码:

# 在manage.py文件中复制过来
import os
​
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mypoject.settings")
    #手写导入django模块
    import django
    django.setup()

2、单表查询之必知必会16条

1、create()

给表添加数据,返回值就是当前被创建数据的对象本身

from app01 import models
res = models.Movie.objects.create(title='西游记', price=999.99)
print(res)  # Movie object   

2、all()

查询表中所有的数据,返回值是queryset对象,并且,只要返回值是queryset对象就可以使用对象 点query 的方式查看获取到的内部SQL语句

    res = models.Movie.objects.all()
    print(res)  # <QuerySet [<Movie: Movie object>, <Movie: Movie object>]>
    print(res.query)
    # SELECT `app01_movie`.`id`, `app01_movie`.`title`, `app01_movie`.`price`, `app01_movie`.`publish_time` FROM `app01_movie`

3、filter()

不传参数就是查询所有,传参数就是查询指定的数据,返回值是列表套queryset对象,当查询对象不存在时,不会报错

pk 就是指当前的主键字段名

    res = models.Movie.objects.filter()  # 不传参数就是查所有对象
    print(res)  # <QuerySet [<Movie: Movie object>, <Movie: Movie object>]>
    # pk 就是指当前的主键字段名
    res1 = models.Movie.objects.filter(pk=1, title='西游记')  # 可以传多个参数是以and连接
    print(res1)  # <QuerySet [<Movie: Movie object>]>

4、update()

更新数据,先查出数据再更新,返回值是受影响的行数

    res = models.Movie.objects.filter(pk=1).update(title='水浒传')
    print(res)  # 1

5、delete()

删除数据,先查出要删除的数据,再删除,返回值是受影响的表和行数 (1, {'app01.Movie': 1})

    res = models.Movie.objects.filter(pk=3).delete()
    print(res)  # (1, {'app01.Movie': 1})

6、first()

先获取到数据对象,取第一个元素

    res = models.Movie.objects.filter().first()
    print(res)  # Movie object
    print(res.title)  # 西游记
    # 因为通过主键只获取到一条数据,所有查第一个就是pk=1的数据
    res = models.Movie.objects.filter(pk=1).first()
    print(res)  # Movie object
    print(res.title)  # 西游记

7、last()

先获取到数据对象,取最后一个元素

    res = models.Movie.objects.filter().last()
    print(res)  # Movie object
    print(res.title, res.price)  # 东游记 888.88
    # 因为通过主键只获取到一条数据,所有查最后一个就是pk=1的数据
    res = models.Movie.objects.filter(pk=1).last()
    print(res)  # Movie object
    print(res.title, res.price)  # 西游记 999.99

8、get()

返回值是直接获取对象本身,当查询条件不存在时会报错,并且必须要传一个参数,不推荐使用

    res = models.Movie.objects.get(pk=1)
    print(res)

9、values()

获取queryset对象是 [{},{}] 不传参数就是获取所有,传参数可以指定获取对应的字段数据

    res = models.Movie.objects.values()
    print(res)
    # <QuerySet [{'id': 1, 'title': '西游记', 'price': Decimal('999.99'), 'publish_time': datetime.date(2014, 1, 8)}, {'id': 2, 'title': '东游记', 'price': Decimal('888.88'), 'publish_time': datetime.date(2011, 1, 8)}]>
    res = models.Movie.objects.values('title', 'price')
    print(res)
    # <QuerySet [{'title': '西游记', 'price': Decimal('999.99')}, {'title': '东游记', 'price': Decimal('888.88')}]>

10、values_list()

获取queryset对象是 [(,)(,)] 不传参数就是获取所有,传参数可以指定获取对应的字段数据

    res = models.Movie.objects.values_list()
    print(res)
    res = models.Movie.objects.values_list('title')
    print(res)  # <QuerySet [('西游记',), ('东游记',)]>

11、order_by()

按照指定字段进行排序,返回queryset对象,对数据库不进行修改

    # 默认升序
    res = models.Movie.objects.order_by('price')
    print(res)
    # 减号就是降序
    res = models.Movie.objects.order_by('-price')
    print(res)

12、count()

统计数据总共有多少条,不能指定参数统计

    res = models.Movie.objects.count()
    print(res)  # 2

13、exclude()

排除什么之外,返回值是排除之外的所有数据

    res = models.Movie.objects.exclude(pk=1)
    # 排除主键是1之外的数据
    print(res)

14、exists()

返回值是布尔值,判断当前对象是否有数据,返回值是布尔值

    res = models.Movie.objects.filter(pk=21).exists()
    print(res) # False

15、reverse()

反转数据,将原排序后的数据反转

    res = models.Movie.objects.order_by('price').reverse()
    print(res)

16、distinct()

去重,去重的前提是必须要有两个数据完全一样才可以,一般有主键,都不会完全一样的

    res = models.Movie.objects.values('title').distinct()
    # 由于有主键,不完全一样,所有不会去重
    print(res)

3、单表查询之神奇的下划线查询

1、查询价格大于200的电影:price__gt 大于 gt

    # 1.查询价格大于200的电影
    res = models.Movie.objects.filter(price__gt=200)
    print(res)

2、查询价格小于900的电影 : price__lt 小于 lt

    res = models.Movie.objects.filter(price__lt=900)
    print(res)

3、查询价格大于等于888.88的电影:price__gte 大于等于 gte

    res = models.Movie.objects.filter(price__gte=888.88)
    print(res)

4、查询价格小于等于999.99的电影:price__lte 小于等于 lte

由于python对小数不是很敏感,所有小数有可能会不会精确找到,最好定义用整数

    res = models.Movie.objects.filter(price__lte=999.99)
    print(res)

5、查询价格是888或999的数据:price__in=[888,999] 注意是列表

由于正常用filter查询多个时是and关系,所以可以使用双下划线的方式

    res = models.Movie.objects.filter(price__in=[888,999])
    print(res)

6、查询价格在800到900之间 电影数据,顾头也顾尾 price__range=(800,900),注意是小括号

    res = models.Movie.objects.filter(price__range=(800,900))
    print(res)

7、查询电影名中包含字母L的电影

  __contains 是区分大小写的

  __icontains 是不区分大小写的

    res = models.Movie.objects.filter(title__contains='l')
    print(res)  # <QuerySet [<Movie: 东游记l>]>
    res = models.Movie.objects.filter(title__icontains='l')
    print(res)  # <QuerySet [<Movie: 东游记L>, <Movie: 东游记l>]>

8、查询2014年、月、日出版的电影 __ year __ day __ month

    res = models.Movie.objects.filter(publish_time__year=2014)
    print(res)
    res = models.Movie.objects.filter(publish_time__month=1)
    print(res)
    res = models.Movie.objects.filter(publish_time__day=8)
    print(res)

4、多表查询之外键字段的增删改查

1、一对多

    # 增:方法一:直接写实际的字段publish_id
    models.Book.objects.create(name='红楼梦', price=888, store=500, sell=800, publish_id = 3)  # publish_id真实表中的的字段
    # 增:方法二:先get方法拿到出版社对象,再给书加对应的出版社
    publish_obj = models.Publish.objects.get(pk=2)
    models.Book.objects.create(name='三体', price=888, store=600, sell=800, publish = publish_obj)  # publish自定义时的字段
    # 改:1.直接指名道姓的修改
    models.Book.objects.filter(pk=9).update(publish_id=3)
    publish_obj = models.Publish.objects.get(pk=1)
    models.Book.objects.filter(pk=9).update(publish=publish_obj)
    # 删除:外键字段在1.x版本默认就是级联更新级联删除,2.x版本需要手动指定

2、多对多

  1、绑定关系:add

add专门给第三张表添加数据,括号内既可以传数字也可以传对象,并且支持传多个

    # 多对多
    #给书籍绑定作者关系
    # 方式一:
    # 1.拿到书对象
    book_obj = models.Book.objects.filter(pk=3).first()
    # 2.书籍对象点虚拟字段authors就跳到第三张表中了,再add绑定
    book_obj.authors.add(1)
    book_obj.authors.add(2,3)  # 可以支持一本书绑定多个作者
# 方式二
    # 1.拿到书籍对象
    book_obj = models.Book.objects.filter(pk=5).first()
    # 2.通过get方法拿到作者对象
    author_obj = models.Author.objects.get(pk=1)
    # 3.给书籍对象点虚拟的authors跳转到第三张表,add对象添加数据
    book_obj.authors.add(author_obj)

  2、移除关系:remove

remove专门给第三张表移除数据,括号内即可以传数字也可以传对象,并且都支持多个

    # 方式一:
    # 1.拿到书对象
    book_obj = models.Book.objects.filter(pk=3).first()
    # 2.书籍对象点虚拟字段authors就跳到第三张表中了,再remove移除关系
    book_obj.authors.remove(1)
    book_obj.authors.remove(2,3)  # 可以支持一本书传多个参数移除关系
# 方式二
    # 1.拿到书籍对象
    book_obj = models.Book.objects.filter(pk=5).first()
    # 2.通过get方法拿到作者对象
    author_obj = models.Author.objects.get(pk=1)
    # 3.给书籍对象点虚拟的authors跳转到第三张表,remove移除关系
    book_obj.authors.remove(author_obj)

  3、修改关系:set

修改两张表的关系,括号内支持传数字和对象,但是需要是可迭代对象,可以set中是元组或者列表

    # 方式一:
    # 1.拿到书对象
    book_obj = models.Book.objects.filter(pk=3).first()
    # 2.书籍对象点虚拟字段authors就跳到第三张表中了,再set设置关系
    book_obj.authors.set((3,))
    book_obj.authors.set((1,3))  # 可以支持一本书传多个参数设置关系
# 方式二
    # 1.拿到书籍对象
    book_obj = models.Book.objects.filter(pk=5).first()
    # 2.通过get方法拿到作者对象
    author_obj = models.Author.objects.get(pk=1)
    # 3.给书籍对象点虚拟的authors跳转到第三张表,set设置关系
    book_obj.authors.set([author_obj])

  4、清空关系:clear

清空第三张表的数据,不需要传任意参数

    # 清空第三表中书的id是5的数据
    book_obj = models.Book.objects.filter(pk=5).first()
    book_obj.authors.clear()

5、多表查询之跨表查询

跨表查询的方式:子查询和链表查询

正向和反向的概念:

  正向:跨表查询的时候 外键字段是否在当前数据对象中,如果在查询另一张表关系,叫做正向

  反向:如果外键字段不在当前的数据对象中,叫做反向

口诀:正向查询按外键字段如果有多个对应加.all(),反向查询按表名小写,如果有多个对应加_set.all()

1、基于对象的跨表查询(子查询)

将一张表的查询结果当做另外一张表的查询条件,分布操作

    # 1.查询书籍pk为5的出版社名称  正向按照外键字段
    book_obj = models.Book.objects.filter(pk=5).first()
    print(book_obj.publish)  # Publish object
    print(book_obj.publish.name)  # 东方出版社
    print(book_obj.publish.addr)  # 东京
    
    #2. 查询书籍pk为3的作者的名字  正向按照外键字段
    book_obj = models.Book.objects.filter(pk=3).first()
    print(book_obj.authors.all())  # 有多个的时候需要用all
    author_list = book_obj.authors.all()
    for author_obj in author_list:
        print(author_obj.name)
        
    # 3.查询作者pk为1的电话号码  正向按照外键字段
    author_obj = models.Author.objects.filter(pk=1).first()
    print(author_obj.author_detail)  # 只有一个对应就不需要用all
    print(author_obj.author_detail.phone)
    
    # 4.查询出版社名称为东方出版社出版的书  反向按照表名小写
    publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    print(publish_obj.book_set.all())  # 有多条对应就要用_set.all()
    
    # 5.查询作者为Jason写过的书
    author_obj = models.Author.objects.filter(name='Jason').first()
    print(author_obj.book_set.all())  # 有多个数据时要加_set.all()
    
    # 6.查询手机号为120的作者姓名
    author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
    print(author_detail_obj.author)  # 反向按照表名小写
    print(author_detail_obj.author.name)

2、基于双下划线的跨表查询(链表查询)

只要表之间有关系,就可以通过正向的外键字段或反向的表名小写,连续跨表操作获取对应的数据

    # 1.查询书籍pk为3的出版社名称
    # 正向
    res = models.Book.objects.filter(pk=3).values('publish__name')
    print(res)
    # 反向
    # res = models.Publish.objects.filter(book__pk=3)  # 拿pk为3的书对应的出版社对象
    res = models.Publish.objects.filter(book__pk=3).values('name')
    print(res)
    
    # 2.查询书籍pk为3的作者名和年龄
    # 正向
    res = models.Book.objects.filter(pk=3).values('authors__name', 'authors__age','name')
    print(res)
    # 反向
    # res = models.Author.objects.filter(book__pk=3)  # 拿到书籍pk=3的作者对象
    res = models.Author.objects.filter(book__pk=3).values('name', 'age', 'book__name')
    print(res)
    
    # 3.查询作者是Jason的年龄和手机号
    # 正向
    res = models.Author.objects.filter(name='Jason').values('author_detail__phone', 'age')
    print(res)
    # 反向
    res = models.AuthorDetail.objects.filter(author__name='Jason').values('phone','author__age')
    print(res)
    
    # 4. 查询书籍pk为3的的作者手机号
    # 正向
    res = models.Book.objects.filter(pk=3).values('authors__author_detail__phone')
    print(res)
    # 反向
    res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone')
    print(res)

6、聚合查询

1、首先需要导入聚合函数

from django.db.models import Max, Min, Avg, Count, Sum

2、关键字:aggregate

    from django.db.models import Max, Min, Sum, Count, Avg
    # 查询所有书的平均价格
    res = models.Book.objects.aggregate(avg_num=Avg('price'))  # avg_num是变量名,可不用
    print(res)
​
    # 查询所有书中最贵的书
    res = models.Book.objects.aggregate(max_num=Max('price'))
    print(res)
​
    # 全部使用
    res = models.Book.objects.aggregate(Min('price'), Count('pk'), Sum('price'))
    print(res)

7、分组查询

关键字:annotate

    from django.db.models import Max, Min, Sum, Count, Avg
    # 1.统计每一本书的作者个数
    # res = models.Book.objects.annotate(author_num=Count('authors')).values('name')
    res = models.Book.objects.annotate(author_num=Count('authors'))
    print(res)
    # 2.统计每个出版社卖的最贵的书
    res= models.Publish.objects.annotate(max_price=Max('book__price')).values('name', 'book__name', 'book__price')
    print(res)
    # 3.统计不止一个作者的图书
    res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('name')
    print(res)
    # 4.查询各个作者的书的总价格
    res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name', 'price_sum')
    print(res)

8、F与Q查询

F:可以获取表中的某个字段对应的值

Q:能够改变查询的条件关系,and or not

首先需要导入F和Q模块

from django.db.models import F, Q
    from django.db.models import F, Q
    # 1.查询所有库存小于卖出的书
    res = models.Book.objects.filter(store__lt=F('sell'))
    print(res)
    # 2.将所有的书价格提高100
    res = models.Book.objects.update(price=F('price')+100)  # 直接对数据库进行操作
    
    # 查询书的名字是西游记或者价格是888的书
    res = models.Book.objects.filter(name='西游记', price=888)  # and关系
    res = models.Book.objects.filter(Q(title='西游记'),Q(price=1000))  # 逗号是and关系
    res = models.Book.objects.filter(Q(title='西游记')|Q(price=1000))  # |是or关系
    res = models.Book.objects.filter(~Q(title='西游记')|Q(price=1000))  # ~是not关系

# Q的高阶用法 # res = models.Book.objects.filter('title'='python入门') ​ q = Q() q.connector = 'or' # q对象默认也是and关系 可以通过connector改变or q.children.append(('title','python入门')) q.children.append(('price',1000)) ​ res = models.Book.objects.filter(q) print(res)

 

 

posted @ 2020-01-09 01:21  Mr沈  阅读(739)  评论(0编辑  收藏  举报