zoukankan      html  css  js  c++  java
  • ORM单表查询,跨表查询,分组查询

                   单表查询之下划线               

    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
    models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
    models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的
    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and
    类似的还有:startswith,istartswith, endswith, iendswith 
    date字段还可以:
    models.Class.objects.filter(first_day__year=2017)
    #获取id大于1且小于10的值
    print(models.Book.objects.filter(id__lt=10,id__gt=1))
    # 查询 id 在 [1, 4, 5, 7]中的结果
    print(models.Book.objects.filter(id__in=[1,4,5,7]))
    # contains 字段包含指定值的
    print(models.Book.objects.filter(title__contains="小单"))
    # icontains 忽略大小写包含指定值
    print(models.Book.objects.filter(title__icontains="NI"))
    # 判断id值在 哪个区间的 SQL语句中的between and  1<= <=3
    print(models.Book.objects.filter(id__range=[1,3]))
    # 日期和时间字段还可以有以下写法
    ret = models.Person.objects.filter(birthday__year=2000)
    ret = models.Person.objects.filter(birthday__year=2000, birthday__month=5)

                            跨表查询操作                  

    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name=models.CharField( max_length=32)
        age=models.IntegerField()
        # 与AuthorDetail建立一对一的关系
        authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
    
    class AuthorDetail(models.Model):
        nid = models.AutoField(primary_key=True)
        birthday=models.DateField()
        telephone=models.BigIntegerField()
        addr=models.CharField( max_length=64)
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name=models.CharField( max_length=32)
        city=models.CharField( max_length=32)
        email=models.EmailField()
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField( max_length=32)
        publishDate=models.DateField()
        price=models.DecimalField(max_digits=5,decimal_places=2)
        # 与Publish建立一对多的关系,外键字段建立在多的一方
        publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
        # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
        authors=models.ManyToManyField(to='Author',)
    View Code

    基于对象查询(子查询)



    按字段(publish)
    一对多 book -----------------> publish
    <----------------
    book_set.all()
     正向查询按字段:
        查询python这本书籍的出版社的邮箱
        python=models.Book.objects.filter(title="python").first()
        print(python.publish.email)
        反向查询按     表名小写_set.all()
        苹果出版社出版的书籍名称
        publish_obj=models.Publish.objects.filter(name="苹果出版社").first()
        for obj in publish_obj.book_set.all():
            print(obj.title)

    按字段(authors.all())
    多对多 book -----------------------> author
    <----------------
                      book_set.all()
        查询python作者的年龄
        python = models.Book.objects.filter(title="python").first()
        for author in python.authors.all():
            print(author.name ,author.age)
    
        查询alex出版过的书籍名称
    
        alex=models.Author.objects.filter(name="alex").first()
        for book in alex.book_set.all():
            print(book.title)
    
    

    按字段 authorDetail
    一对一 author -----------------------> authordetail
    <----------------
    按表名 author
        查询alex的手机号
        alex=models.Author.objects.filter(name='alex').first()
        print(alex.authorDetail.telephone)
        查询家在山东的作者名字
        ad_list=models.AuthorDetail.objects.filter(addr="shandong")
        for ad in ad_list:
            print(ad.author.name)
        对应的sql:
         select publish_id from Book where title="python"
         select email from Publish where nid =   1

      基于queryset和__查询(join查询)  


    正向查询:按字段 反向查询:表名小写

    查询python这本书籍的出版社的邮箱
    ret=models.Book.objects.filter(title="python").values("publish__email")
    print(ret.query)

    select publish.email from Book
    left join Publish on book.publish_id=publish.nid
    where book.title="python"

    苹果出版社出版的书籍名称
    方式1:
    ret1 = models.Publish.objects.filter(name="苹果出版社").values("book__title")
    print("111111111====>", ret1.query)
    # 方式2:
    ret2 = models.Book.objects.filter(publish__name="苹果出版社").values("title")
    print("2222222222====>", ret2.query)

    查询alex的手机号
    方式1:
    ret = models.Author.objects.filter(name="alex").values("authorDetail__telephone")

    方式2:
    models.AuthorDetail.objects.filter(author__name="alex").values("telephone")

    查询手机号以151开头的作者出版过的书籍名称以及书籍对应的出版社名称

    ret = models.Book.objects.filter(authors__authorDetail__telephone__startswith="151").values('title', "publish__name")
    print(ret.query)

    # 1.正向查询 基于对象 跨表查询
    book_obj = models.Book.objects.all().first()  #对象
    ret = book_obj.publisher  # 和我这本书关联的出版社对象
    print(ret, type(ret))
    ret = book_obj.publisher.name  # 和我这本书关联的出版社对象
    print(ret, type(ret))
    # 2.利用双下划线 跨表查询 双下划线就表示跨了一张表,基于Queryset
    ret = models.Book.objects.filter(id=1).values_list("publisher__name")
    print(ret) #等同于 print( models.Book.objects.all().first().publisher.name)
    print("反向查询".center(80, "*"))
    # 反向查询 1. 基于对象查询
    publisher_obj = models.Publisher.objects.get(id=1)  # 得到一个具体的对象
    # ret = publisher_obj.book_set.all()  #表名_set
    ret = publisher_obj.books.all() #如果设置了related_name="books"
    print(ret)
    # 2. 基于双下划线 基于Queryset
    ret = models.Publisher.objects.filter(id=1).values_list("book__title")
    print(ret)
    View Code

                         聚合查询                 

    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
    用到的内置函数:from django.db.models import Avg, Sum, Max, Min, Count
    from django.db.models import Avg, Sum, Max, Min, Count
    book_obj=models.Book.objects.all()
    print(book_obj.aggregate(Max("price"))) #{'price__max': Decimal('9999.99')}
    #指定一个名称
    print(book_obj.aggregate(max_price=Max("price"))) #{'max_price': Decimal('9999.99')}
    #生成多个聚合
    print(book_obj.aggregate(Max("price"),Min("price"),Avg("price"))) #{'price__max': Decimal('9999.99'), 'price__min': Decimal('10.00'), 'price__avg': 1507.141429}

                    分组查询                     

    1.和sql对比:
    1.models.Employee Employee相当于sql中的from 后面的表名
    2.annotate前面的values值相当于group by的字段
    3.(a=Avg("salary"))里面如是跨表查询就需要使用双下划线,正查就字段__另一张表的字段,反查就另一张表明__字段
    4.annotate后面的values 是select的字段
    对应格式:select __ from ___ inner join ———— on ... group by ____
    2.关键点:
    1.queryset对象.annotate() annotate前面是queryset对象
    2.annotate进行分组统计,按前面select的字段进行group by
    3.annotate()返回值依然是queryset对象,增加了分组统计之后的键值对

    1.ORM中values或者values_list 里面写什么字段,就相当于select 什么字段
     ORM分组查询 每个部门名称及部门的平均年龄
    ret = models.Employee.objects.all().values("dept", "age")
    SQL语句
    """
    SELECT `employee`.`dept`, `employee`.`age` FROM `employee` LIMIT 21; args=()
    """
    2.ORM中 annotate 前面是什么就按照什么分组
    from django.db.models import Avg  
    ret = models.Employee.objects.values("province").annotate(a=Avg("salary")).values("province", "a")
    相当于:
    SELECT `employee`.`province`, AVG(`employee`.`salary`) AS `a` FROM `employee` GROUP BY `employee`.`province` ORDER BY NULL LIMIT 21; args=()
    print("分组查询".center(80, "*"))
    3. ORM跨表分组查询,queryset对象跨表查询时使用双下划线
    ret = models.Person.objects.values("dept_id").annotate(a=Avg("salary")).values("dept__name", "a")
    反向:
    """
    SELECT `dept`.`name`, AVG(`person`.`salary`) AS `a` FROM `person` INNER JOIN `dept` ON (`person`.`dept_id` = `dept`.`id`) GROUP BY `person`.`dept_id`, `dept`.`name` ORDER BY NULL LIMIT 21; args=()
    """
    4.查询每一个部门的名称和人数
    #正向查询:
    models.emp.objects.values("dept_id").annotate(c=Count("name")).values("dept__name","c")
    #反向查询
    models.dep.objects.values("name").annotate(c=Count("emp__name")).values("name","c")
    SQL: select dep_name Count(emp.name) from emp inner join dep on  .... group by dep_id
    
    5.查询每一个作者的名字及出版过的书籍的最高价
    models.Author.objects.values('id').annotate(c=Max('book__price')).values("name","c")
    ##多对多的关系,在sql中跨了多张表
    select __ from author inner join book_authors on .... inner join ... group by author.name
    6.查询每一本书作者的个数
    models.Book.objects.values("id").annotate(c=Count("authors__name")).values("title","c")
    ret=models.Book.objects.all().annotate(author_num=Count("author"))
    for book in ret:
        print("书名:{},作者数量:{}".format(book.title, book.author_num))
    #查询每一个分类的名称及对应的文章数 models.Category.objects.values("id").annotate(c=Count("article__title")).values("title","c") 
    7.统计不止一个作者的图书(过滤完后显示) models.Book.objects.values("title").annotate(c=Count("authors__name")).filter(c__gt=1).values('name',"c")
    8.查询各个作者出的书的总价格 ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")) for i in ret: print(i, i.name, i.price_sum)
    extra  --> 在执行ORM查询的时候执行额外的SQL语句
    # 查询person表,判断每个人的工资是否大于2000
    ret = models.Person.objects.all().extra(
        select={"gt": "salary > 2000"}
    )
    相当于:
    SELECT (salary > 2000) AS `gt`, `person`.`id`, `person`.`name`, `person`.`salary`, `person`.`dept_id` FROM `person` LIMIT 21; args=()
    直接执行原生的SQL语句,类似pymysql的用法
    from django.db import connection
    cursor = connection.cursor()  # 获取光标,等待执行SQL语句
    cursor.execute("""SELECT * from person where id = %s""", [1])
    row = cursor.fetchone()
    print(row)
                       F查询和Q查询         
    F查询
    要对两个字段的值做比较,Django 提供 F() 来做这样的比较。
    F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
    1.查询评论数大于收藏数的书籍
    from django.db.models import F
    models.Book.objects.filter(commnet_num__gt=F('keep_num'))
    2.Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
    models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)
    3修改操作也可以使用F函数,比如将每一本书的价格提高30元
    # 具体的对象没有update(),QuerySet对象才有update()方法
    models.Book.objects.all().update(price=F("price")+30)
    刷单 把每一本书的卖出数都乘以3
    obj = models.Book.objects.first()
    obj.maichu = 1000 * 3
    obj.save()
    4.给每一本书的书名后面加上 第一版
    from django.db.models.functions import Concat
    from django.db.models import Value
    models.Book.objects.update(title=Concat(F("title"), Value("第一版")))
        Q查询     
    如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
    from django.db.models import Q
    1.查询 卖出数大于1000,并且 价格小于100的所有书
    ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100)
    print(ret)
    2.查询 卖出数大于1000,或者 价格小于100的所有书
    ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100))
    3. Q查询和字段查询同时存在时, 字段查询要放在Q查询的后面
    ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板")
    Q().children查询
    Q().children,通过字段字符串查询
            q=Q()
            ##查询出title字段中值为go的对象
            q.children.append(("title","go"))
            Book.objects.filter(q)
            Out[11]: <QuerySet [<Book: go>]>
            ##查询出title字段中值含有g的对象
            q.children.append(("title__contains","g"))
            Book.objects.filter(q)
            Out[13]: <QuerySet [<Book: go>]>
            q=Q()  #不同的字段之间的关系默认为and
            q.children.append(("title__contains","g"))
            q.children.append(("price",100))
            Book.objects.filter(q)
            Out[17]: <QuerySet []>
            q=Q()
            q.connector="or"  #不同的字段之间的关系更改为or
            q.children.append(("title__contains","g"))
            q.children.append(("price",100))
            Book.objects.filter(q)
            Out[22]: <QuerySet [<Book: go>]>
     




  • 相关阅读:
    Ubuntu16.04+GTX2070+Driver418.43+CUDA10.1+cuDNN7.6
    N皇后问题
    Linux Bash之通配符
    Linux Bash之正则表达式
    Linux Bash文本操作之grep篇
    Linux Bash文本操作之sed篇其二
    Integer对象两种创建方式的比较
    Class文件版本号
    group by、group_concat()、if()
    字节码命令与Java语言在语义描述能力上的差异
  • 原文地址:https://www.cnblogs.com/zgf-666/p/9119126.html
Copyright © 2011-2022 走看看