ORM查询操做

ORM查询操做

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

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

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

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

一、create()

给表添加数据,返回值就是当前被建立数据的对象自己数据库

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

二、all()

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

    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`

三、filter()

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

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>]>

四、update()

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

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

五、delete()

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

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

六、first()

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

    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)  # 西游记

七、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

八、get()

返回值是直接获取对象自己,当查询条件不存在时会报错,而且必需要传一个参数,不推荐使用blog

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

九、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')}]>

十、values_list()

获取queryset对象是 [(,)(,)] 不传参数就是获取全部,传参数能够指定获取对应的字段数据

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

十一、order_by()

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

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

十二、count()

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

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

1三、exclude()

排除什么以外,返回值是排除以外的全部数据

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

1四、exists()

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

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

1五、reverse()

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

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

1六、distinct()

去重,去重的前提是必需要有两个数据彻底同样才能够,通常有主键,都不会彻底同样的

    res = models.Movie.objects.values('title').distinct()
    # 因为有主键,不彻底同样,全部不会去重
    print(res)

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

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

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

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

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

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

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

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

因为python对小数不是很敏感,全部小数有可能会不会精确找到,最好定义用整数

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

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

因为正经常使用filter查询多个时是and关系,因此可使用双下划线的方式

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

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

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

七、查询电影名中包含字母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>]>

八、查询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)

四、多表查询以外键字段的增删改查

一、一对多

    # 增:方法一:直接写实际的字段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版本须要手动指定

二、多对多

  一、绑定关系: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)

  二、移除关系: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)

  三、修改关系: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])

  四、清空关系:clear

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

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

五、多表查询之跨表查询

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

正向和反向的概念:

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

  反向:若是外键字段不在当前的数据对象中,叫作反向

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

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

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

    # 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)

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

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

    # 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)

六、聚合查询

一、首先须要导入聚合函数

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

二、关键字: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)

七、分组查询

关键字: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)

八、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)
相关文章
相关标签/搜索