单表查询,多表查询,分组查询,聚合函数,F与Q

一、单表查询前期准备

1、新建数据库修改django默认配置数据库

去django项目下的settings修改数据库参数

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day53',     # 写你自己的数据库
        'USER': 'root',
        'PASSWORD': '123456',   # 写你自己的密码
        'HOST': '127.0.0.1',
        'POST': 3306,
        'CHARSET': 'utf8'
    }
}

2、去项目app应用下或者与项目同名同名文件下的__init__文件下修改数据库

import pymysql
pymysql.install_as_MySQLdb()

3、创建数据

from django.db import models

# Create your models here.

class Movie(models.Model):
    title = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateField()    # 年月日
    # publish_time = models.DateTimeField()   # 年月日 时分秒
    '''
    auto_now:每次修改数据的时候 都会自动将最新的更新时间记录下来
    auto_now_add:只有在创建数据的将创建时候自动记录下来  之后不会自动改变
    '''
    def __str__(self):  # 为了演示的效果更好,我们用这个方法
        return self.title  # 这个方法在print时触发 我们让它返回自己的title

注意:记得创建好数据字段之后一定要同步到数据库中
python manage.py makemigrations
python manage.py migrate

4、创建测试单个文件的测试环境

随便在一个文件下去添加测试环境都可以,这里就有一个默认的tests文件,我们就在这里添加,你也可以自己手动创建文件然后添加测试环境

from django.test import TestCase
# Create your tests here.
import os
import sys
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
    import django
    django.setup()
    from app01 import models
    models.Movie.objects.all()

 二、单表查询

    '''
    单表查询必知必会16条
        1、create()
        2、all()
        3、filter()
        4、update()
        5、delete()
        6. first()
        7. last()
        8.get()
        9.values()
        10.values_list()
        11.order_by()
        12.count()
        13.exclude()
        14.exists()
        15.distinct()
        16、reverse()
    '''

1、create

    # 1、create 增    返回值就是当前被创建数据的对象本身
    # 日期可以手动给
    models.Movie.objects.create(title='3D肉蒲团', price=999.23, publish_time='2016-1-1')

    # 还可以直接传日期对象
    from datetime import date
    ctime = date.today()
    models.Movie.objects.create(title='西游记', price=666.66, publish_time=ctime)



#这里我已经添加过很多数据啦,就不一一演示啦

2、all

    # 2、all 查      拿到的是queryset对象
    res = models.Movie.objects.all()
    print(res)

 3、filter

 # 3、filter          拿到的是queryset对象
    res = models.Movie.objects.filter(id=1)
    res = models.Movie.objects.filter(pk=1)
    res = models.Movie.objects.filter(pk=1, title='python从入门到放弃')  # 括号内可以放多个条件默认是and关系

    # # pk指代的就是当前表的主键的字段名 可以自动查找非常方便
    # # 只要是queryset 对象 就可以通过 点query 方式查看到获取当前对象内部的SQL语句
    print(res.query)

 4、get

# 4、get         直接获取对象本身   当查询条件不存在时不推荐使用会报错
    res = models.Movie.objects.get(pk=1)
    print(res)
    print(res.title)
    print(res.price)

    res = models.Movie.objects.get(pk=1000)

 5、values

# 5、values    queryset对象    [{},{},{}]
    res = models.Movie.objects.values('title', 'publish_time')
    print(res)

 6、values_list

# 6、values_list  queryset对象 [(),(),()]   获取指定字段对应的数据

    res = models.Movie.objects.values_list('title', 'price')
    print(res)

 7、first

# 7、first    数据对象   取第一个元素对象
    res = models.Movie.objects.filter().first()
    print(res)

 8、last

# 8、last     数据对象   取最后一个元素对象
    res = models.Movie.objects.filter().last()
    res = models.Movie.objects.last()  #也可以简写
    print(res)

9、update

9、update   返回值是受影响的行数
    res = models.Movie.objects.filter(pk=2).update(title='金瓶mei22')
    print(res)

10、delete

# 10、delete
    res = models.Movie.objects.filter(pk=2).delete()
    print(res)

11、count

# 11、count   统计数据条数
    res = models.Movie.objects.filter(pk=1).count()
    print(res)

12、order_by

# 12、order_by   按照指定的字段排序   默认是升序  加个-是降序
    # res = models.Movie.objects.order_by('price')
    res = models.Movie.objects.order_by('-price')

    print(res)

13、exclude

# 13、exclude 排除什么字段之外的数据
    res = models.Movie.objects.exclude(pk=1)
    print(res)

14、exists

# 14、exists   判断前面的对象是否有数据    返回的是布尔值
    res = models.Movie.objects.filter(pk=1000).exists()
    print(res)

15、reverse

# 15、reverse    反转
    res = models.Movie.objects.order_by().reverse()
    print(res)

16、distinct

# 16、distinct   去重的前提必须是有完全一样的数据才可以
    # res = models.Movie.objects.all().distinct()
    res = models.Movie.objects.values('title', 'price').distinct()
    # 要指定数据类型之后可以去重
    print(res)

 三、神奇的双下划线查询

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

    # # 2、查询介个小于500电影
    # res = models.Movie.objects.filter(price__lt=500)   # __lt代表小于
    # print(res)
    #
    # 3、查询价格大于等于876.23的电影
    # res = models.Movie.objects.filter(price__gte=876.23)   # __gte代表大于等于
    # print(res)

    # 4、查询价格小于等于876.23的电影
    # res = models.Movie.objects.filter(price__lte=876.23)
    # print(res)

    # 5、查询价格是123 或666 或876
    # res = models.Movie.objects.filter(price__in=[123, 666, 876])
    # print(res)

    # 6、查询介个在200到900之间的电影   注意这个顾头也顾尾
    # res = models.Movie.objects.filter(price__range=(200, 900))
    # print(res)

    # 7、查询电影名中包含字母p的电影
    '''
    模糊查询:
        关键字:like
        关键符号: 
            % :任意个数任意字符
            _ : 单个任意字符
    '''
    res = models.Movie.objects.filter(title__contains='P')  # 默认区分大小写
    res = models.Movie.objects.filter(title__icontains='P')  # i代表ignore加了以后忽略大小写

    # 8、查询2014年出版的电影
    res = models.Movie.objects.filter(publish_time__year=2014)
    print(res)
    
    # 9、查询电影是1月份出版的电影
    res = models.Movie.objects.filter(publish_time__month=1)
    print(res)

四、图书管理系统表的创建以及数据录入

1、创建类

from django.db import models
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish_time = models.DateField(auto_now_add=True)   # 加上auto_now_add=True该字段新增数据自动添加

    # 书籍与出版社  一对多    外键字段建在多的一方
    publish = models.ForeignKey(to='Publish')

    # 书籍与作者   多对多     外键字段建在任意一方均可 这里推荐你建在查询频率高的表上
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 作者与作者详情表  一对一  外键字段建在任意一方均可  同样推荐建在查询频率高的表上
    author_detail = models.OneToOneField(to='AuthorDetail')

class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)
注意:记得创建好数据字段之后一定要同步到数据库中
python manage.py makemigrations
python manage.py migrate
# 然后自己去navicate中添加些数据

五、外键字段的增删改查

  我们把这个外键字段分为两类

1、一对多的增删改查

    # 一对多    publish
    # # 1、增  方式一直接写实际的表字段publish_id
    # models.Book.objects.create(title='三国演义', price=123.23, publish_id=2)
    #
    # # 2、增  方式二
    # publish_obj = models.Publish.objects.get(pk=1)
    # models.Book.objects.create(title='金瓶MEI', price=66.66, publish=publish_obj)

    #


    #
    # models.Book.objects.filter(pk=1).update(publish_id=3)
    # publish_obj = models.Publish.objects.get(pk=4)
    # models.Book.objects.filter(pk=1).update(publish=publish_obj)

    #
    '''
    外键字段在1.x版本中默认的是级联更新删除的
    2.x版本中 则需要你自己手动去指定
    参考博客: https://www.cnblogs.com/bladecheng/p/11629061.html
    '''

2、多对多的增删改查

    # 1、给书籍绑定作者关系    add
    # book_obj = models.Book.objects.filter(pk=1).first()   # 拿到书对象中的第一本书
    # # 书籍和作者的关系是由第三方表决定 也就意味着你要操作第三方表
    # print(book_obj.authors)   # 这句话就意味着书籍对象点虚拟字段authors就类似于已经跨到书籍和作者的第三方表中去了

    # 然后给书籍和作者之间添加关系
    # 方式一、传数字
    # book_obj.authors.add(1)  # 这句话的意思是给书籍绑定一个主键为1的作者
    # book_obj.authors.add(2,3)

    # 方式二:传对象
    # author_obj = models.Author.objects.get(pk=1)
    # author_obj1 = models.Author.objects.get(pk=3)
    # book_obj.authors.add(author_obj, author_obj1)

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

    # 2 移除书籍与作者的绑定关系  remove
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.remove(2)
    # book_obj.authors.remove(1,3)
    # author_obj = models.Author.objects.get(pk=2)
    # author_obj1 = models.Author.objects.get(pk=3)
    # book_obj.authors.remove(author_obj)
    # book_obj.authors.remove(author_obj,author_obj1)
    """
    remove专门给第三张关系表移除数据
        括号内即可以传数字也可以传对象  并且都支持传多个
    """

    # 3 修改书籍与作者之间的关系  set
    # book_obj = models.Book.objects.filter(pk=1).first()
    # # # book_obj.authors.set((3,))
    # # book_obj.authors.set((2, 3))  # 可以支持传多个参数
    #
    # # 可以传对象
    # author_obj = models.Author.objects.get(pk=2)
    # author_obj1 = models.Author.objects.get(pk=3)
    # # book_obj.authors.set((author_obj,))
    # book_obj.authors.set([author_obj,author_obj1])

    """
        set 修改书籍与作者的关系 
            括号内支持传数字和对象 但是需要是可迭代对象
        """

    # 4、清空书籍与作者的关系   clear
    book_obj = models.Book.objects.filter(pk=1).first()

    book_obj.authors.clear()  # 去第三张表中清空书籍为1的所有数据
    """
        clear()  清空关系 
        不需要任何的参数
        """

 六、跨表查询以及正向反向

1、回顾跨表查询

    跨表查询的方式
        1.子查询  将一张表的查询结果当做另外一张表的查询条件
            正常解决问题的思路 分步操作
        2.链表查询
            inner join
            left join
            right join
            union
    建议:在写sql语句或者orm语句的时候 千万不要想着一次性将语句写完 一定要写一点查一点再写一点
    

2、正反向的概念

     正向
            跨表查询的时候 外键字段是否在当前数据对象中 如果
            查询另外一张关系表  叫正向
            
        反向
            如果不在反向
        
        口诀
            正向查询按外键字段
            反向查询按表名小写(或者有些时候在表名后面加上_set.all())
                             
    """

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

# 1.查询书籍pk为1的出版社名称
    # 先拿到书籍对象
    # book_obj = models.Book.objects.filter(pk=1).first()
    # 正向查询按字段(字段即为绑定的外键)
    # print(book_obj.publish)   # Publish object
    # print(book_obj.publish.name)  #西方出版社
    # print(book_obj.publish.addr)  #西京

    # 2.查询书籍pk为2的所有作者的姓名
    # 先拿到书籍对象
    # book_obj = models.Book.objects.filter(pk=2).first()

    # 书查作者 正向
    # print(book_obj.authors)  #app01.Author.None
    # print(book_obj.authors.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)  #AuthorDetail object
    # print(author_obj.author_detail.phone)
    # print(author_obj.author_detail.addr)

    """
        正向查询的时候 当外键字段对应的数据可以有多个的时候需要加.all()
        否则点外键字典即可获取到对应的数据对象
        """

    # 4.查询出版社名称为东方出版社出版过的书籍
    # publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    # 出版社到书反向
    # print(publish_obj.book_set)  #app01.Book.None
    # print(publish_obj.book_set.all())

    # 5.查询作者为jason写过的书
    # author_obj = models.Author.objects.filter(name='jason').first()
    # print(author_obj.book_set)   #app01.Book.None
    # print(author_obj.book_set.all())

    # 6.查询手机号为120的作者姓名
    # author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
    # # print(author_detail_obj.author) # Author object
    # print(author_detail_obj.author.name)
    # print(author_detail_obj.author.age)

    '''
    基于对象的反向查询 表名小写是否需要加_set.all()
    一对一不需要加
    一对多和多对多的时候需要加
    '''

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

# 1.查询书籍pk为1的出版社名称
    # # 正向
    # res = models.Book.objects.filter(pk=1).values('publish__name')   # 写外键字段就意味着你已经在外键字段关联的那张表中
    # print(res)  #<QuerySet [{'publish__name': '西方出版社'}]>

    # 反向
    # # res = models.Publish.objects.filter(book__pk=1)    # 拿出版过pk为1的书籍对应的出版社
    # res = models.Publish.objects.filter(book__pk=1).values('name')
    # print(res)

    # 2.查询书籍pk为1的作者姓名和年龄
    # 正向
    # res = models.Book.objects.filter(pk=1).values('title', 'authors__name', 'authors__age')
    # print(res)

    # 反向
    # # res = models.Author.objects.filter(book__pk=1)    # 拿出出版过书籍pk为1的作者
    # res = models.Author.objects.filter(book__pk=1).values('name', 'age', 'book__title')
    # 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)

    # 查询书籍pk为的1的作者的手机号
    # 正向
    # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    # print(res)
    
    # 反向
    # res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
    # print(res)
    
    '''
    只要表之间有关系  你就可以通过正向的外键字段或者反向的表名小写 连续跨表操作
    '''

九、聚合查询

from django.db.models import Max, Min, Avg, Count, Sum  # 聚合函数需要你自己先导入
    '''
    聚合查询关键字:
            aggregate
    '''
    #查询所有书的平均价格
    res = models.Book.objects.aggregate(avg_num=Avg('price'))  # 需要自己起一个别名
    print(res)
    #查询价格最贵的书
    res = models.Book.objects.aggregate(max_num=Max('price'))
    print(res)
    #全部使用一遍
    res = models.Book.objects.aggregate(Avg("price"), Max("price"), Min("price"),Count("pk"),Sum('price'))
    print(res)

十、分组查询

'''
    分组查询关键字:
            annotate
    '''

    # 1.统计每一本书的作者个数
    # res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')
    # print(res)

    # 2.统计出每个出版社卖的最便宜的书的价格
    # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title')
    # print(res)

    # 3.统计不止一个作者的图书
    # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title')
    # print(res)

    # 4.查询各个作者出的书的总价格
    # res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum')
    # print(res)

    # 5.如何按照表中的某一个指定字段分组
    """
    res = models.Book.objects.values('price').annotate()  就是以价格分组
    """

十一、F与Q查询

    from django.db.models import F,Q
    # # 1.查询库存数大于卖出数的书籍
    # res = models.Book.objects.filter(kucun__gt=F('maichu'))
    # print(res)

    # 2.将所有书的价格提高100
    res = models.Book.objects.update(price=F('price') + 100)

    """
        帮你获取到表中某个字段对应的值
        """

    # Q能够改变查询的条件关系   and or not
    # 1、查询数电名字是python入门或者价格是1000的书籍
    # res = models.Book.objects.filter(title='python入门', price=1000)  # 这种方法实现不了
    # res = models.Book.objects.filter(Q(title='python入门'), Q(price=1000))  # 逗号是and关系

    # res = models.Book.objects.filter(Q(title='python入门')|Q(price=1000))  # |是or关系
    # res = models.Book.objects.filter(~Q(title='python入门')|Q(price=1000))  # ~是not关系
    #
    # print(res.query)


    # Q的高阶用法
    # 想要实现类似以以下的功能,就必须要使用Q的高阶用法
    # res = models.Book.objects.filter(('title'='python入门'))


    q = Q()
    q.connector = 'or'   # q对象默认的也是and关系   这句话将下面的添加的两行变成or关系
    q.children.append(('title', 'python入门'))
    q.children.append(('price', 1000))
    res = models.Book.objects.filter(q)
    print(res)

 

猜你喜欢

转载自www.cnblogs.com/yafeng666/p/12169151.html