• Django跨表查询相关


     

    今日内容

    一般操作

            补充

    related_name

    反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。

    related_query_name

    反向查询操作时,使用的连接前缀,用于替换表名。

    两个不能同时用

     

              如果设置了related_name 那么就是以后列表查询就要写related_name定义的

     

    多对多关联关系的三种方式 

    方式一:自行创建第三张表

    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")
    
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者姓名")
    
    # 自己创建第三张表,分别通过外键关联书和作者
    class Author2Book(models.Model):
        author = models.ForeignKey(to="Author")
        book = models.ForeignKey(to="Book")
    
    class Meta:
            unique_together = ("author", "book")
    
     
    
    import os
    
     
    
    调用不了orm方法只能通过models来管理
    
    if __name__ == '__main__':
    
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_demo.settings")
    
        import django
    
        django.setup()
    
     
    
        # ORM查询操作
    
        from app02 import models
    
     
    
        first_book = models.Book.objects.first()
    
     
    
        # 找到第一本书
    
        # 查询
    
        # ret = models.Book.objects.first().author2book_set.all().values("author__name")
    
        # print(ret)
    
     
    
        ret = models.Book.objects.filter(id=1).values("author2book__author__name")
    
        print(ret)
    
     
    
        # first_book.author.set()
    
        models.Author2Book.objects.create(book=first_book, author_id=1)
    
        # 清空
    
        models.Author2Book.objects.filter(book=first_book).delete()
    
     
    
        # 2. set
    
        # models.Book.objects.first().author.set([2,3])
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 3. add
    
        # models.Book.objects.first().author.add(1)
    
     
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 4. remove
    
        # models.Book.objects.first().author.remove(3)
    
     
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 5.clear
    
        # models.Book.objects.first().author.clear()
    
        #
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 6. all
    
        # ret = models.Book.objects.first().author.all()
    
        # print(ret)
    View Code

    方式二:通过ManyToManyField自动创建第三张表

     

    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name="书名")
    
    # 通过ORM自带的ManyToManyField自动创建第三张表
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name="作者姓名")
        books = models.ManyToManyField(to="Book", related_name="authors")

    方式三:设置ManyTomanyField并指定自行创建的第三张表

      

         

    注意:

    当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。

    但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。

     

    单表查询之神奇的双下划线

    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)

    ForeignKey操作一对多联表查询

    正向查找

     对象查找(跨表)

    语法:

    对象.关联字段.字段

     

    示例:

    book_obj = models.Book.objects.first()  # 第一本书对象
    print(book_obj.publisher)  # 得到这本书关联的出版社对象
    print(book_obj.publisher.name)  # 得到出版社对象的名称

      字段查找(跨表)

    语法:

    关联字段__字段

    示例:

    print(models.Book.objects.values_list("publisher__name"))

     

    反向操作 (就是被关联的表查找)

    对象查找

    语法:

    obj.表名_set

    示例:

    publisher_obj = models.Publisher.objects.first()  # 找到第一个出版社对象
    books = publisher_obj.book_set.all()  # 找到第一个出版社出版的所有书
    titles = books.values_list("title")  # 找到第一个出版社出版的所有书的书名

    字段查找

    语法:

    表名__字段

    基于双下划线查询

    示例:

    titles = models.Publisher.objects.values_list("book__title")

     

    ManyToManyField多对多查询

    class RelatedManager

    "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。

    它存在于下面两种情况:

                            i.        外键关系的反向查询

                           ii.        多对多关联关系

    简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。

    方法

    create()

    创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。

    >>> import datetime
    >>> models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())

    add()

    把指定的model对象添加到关联对象集中。

    添加对象

    >>> author_objs = models.Author.objects.filter(id__lt=3)
    >>> models.Book.objects.first().authors.add(*author_objs)

    添加id

    >>> models.Book.objects.first().authors.add(*[1, 2])

    set()

    更新model对象的关联对象。

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.set([2, 3])

    remove()

    从关联对象集中移除执行的model对象

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.remove(3)

    clear()

    从关联对象集中移除一切对象。

    >>> book_obj = models.Book.objects.first()
    >>> book_obj.authors.clear()

    注意:

    对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

    举个例子:

    ForeignKey字段没设置null=True时,
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        publisher = models.ForeignKey(to=Publisher)
    
    没有clear()和remove()方法:
    
    >>> models.Publisher.objects.first().book_set.clear()
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
    AttributeError: 'RelatedManager' object has no attribute 'clear'
    
    当ForeignKey字段设置null=True时,
    
    class Book(models.Model):
        name = models.CharField(max_length=32)
        publisher = models.ForeignKey(to=Class, null=True)
    
    此时就有clear()和remove()方法:
    
    >>> models.Publisher.objects.first().book_set.clear()
    
     
    
     # 多对多操作
    
        # 1. create
    
        # 做了两件事情:
    
        # 1. 创建了一个新的作者,2. 将新创建的作者和第一本书做关联
    
        # ret = models.Book.objects.first().author.create(
    
        #     name="张曌",
    
        #     age=16,
    
        #     phone="18012575998",
    
        #     detail_id=4
    
        # )
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 2. set
    
        # models.Book.objects.first().author.set([2,3])
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 3. add
    
        # models.Book.objects.first().author.add(1)
    
     
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 4. remove
    
        # models.Book.objects.first().author.remove(3)
    
     
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 5.clear
    
        # models.Book.objects.first().author.clear()
    
        #
    
        # ret = models.Book.objects.first().author.all().values("id")
    
        # print(ret)
    
     
    
        # 6. all
    
        # ret = models.Book.objects.first().author.all()
    
        # print(ret) 
    View Code

    注意:

    对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

    聚合查询和分组查询(重要)

    聚合

    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

    键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

    用到的内置函数:

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

    示例:

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

    >>> models.Book.objects.all().aggregate(Avg("price"))
    {'price__avg': 13.233333}

    如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

    >>> models.Book.objects.aggregate(average_price=Avg('price'))
    {'average_price': 13.233333}

    如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

    >>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
    {'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}

    分组

    我们在这里先复习一下SQL语句的分组。

    假设现在有一张公司职员表:

     

     我们使用原生SQL语句,按照部分分组求平均工资:

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

    ORM查询:

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

    连表查询的分组:

     

     

    SQL查询:

    select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;

    ORM查询:

    from django.db.models import Avg
    models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

    更多示例:

    示例1:

           

    练习orm查询练习题

    # ORM查询操作
        from app01 import models
    
        # 1. 查找所有书名里包含番茄的书
        # ret = models.Book.objects.filter(title__contains='番茄')
        # print(ret)
        # 2. 查找出版日期是2017年的书
        # ret = models.Book.objects.filter(publish_date__year=2017)
        # print(ret)
        # 3. 查找出版日期是2017年的书名
        # ret = models.Book.objects.filter(publish_date__year=2017).values("title")
        # print(ret)
    
        # 查找价格大于10元的书
        # ret = models.Book.objects.filter(price__gt=10)
        # print(ret)
    
        # 查找价格大于10元的书名和价格
        # ret = models.Book.objects.filter(price__gt=10).values("title", "price")
        # print(ret)
        # 查找memo字段是空的书
        # ret = models.Book.objects.filter(memo__isnull=True)
        # print(ret)
    
        # 查找在北京的出版社
        # ret = models.Publisher.objects.filter(city='北京')
        # print(ret)
    
        # 查找名字以沙河开头的出版社
        # ret = models.Publisher.objects.filter(name__startswith="沙河")
        # print(ret)
    
        # 查找作者名字里面带'小'字的作者
        # ret = models.Author.objects.filter(name__contains='小')
        # print(ret)
    
        # 查找年龄大于30岁的作者
        # ret = models.Author.objects.filter(age__gt=30)
        # print(ret)
    
        # 查找手机号是155开头的作者
        # ret = models.Author.objects.filter(phone__startswith='155')
        # print(ret)
    
        # 查找手机号是155开头的作者的姓名和年龄
        # ret = models.Author.objects.filter(phone__startswith='155').values("name", "age")
        # print(ret)
    
        # 连表查询
        # book_obj = models.Book.objects.first()
        # 基于对象查找
        # ret = book_obj.publisher.name
        # print(ret)
        # 基于双下划线的跨表查询
        # ret = models.Book.objects.values("publisher__name", "publisher__city").first()
        # print(ret)
    
        # 正向查找
        # 查找书名是“番茄物语”的书的出版社
        # 1. 基于对象的查找方式
        # ret = models.Book.objects.get(title="番茄物语").publisher
        # print(ret)
        # 查找书名是“番茄物语”的书的出版社所在的城市
        # ret = models.Book.objects.get(title="番茄物语").publisher.city
        # print(ret)
        # 2. 基于双下划线的夸表查询
        # ret = models.Book.objects.filter(title="番茄物语").values("publisher__city")
        # print(ret)
    
        # 外键的反向查找
        # 1. 基于对象的查找方式
        # publisher_obj = models.Publisher.objects.first()
        # ret = publisher_obj.book_set.all()
        # print(ret)
        # 如果设置了 related_name="books"
        # publisher_obj = models.Publisher.objects.first()
        # ret = publisher_obj.books.all()
        # print(ret)
    
        # 基于双下划线的跨表查询
        # ret = models.Publisher.objects.filter(id=1).values("books__title")
        # print(ret)
    
        # 如果设置了 related_query_name="zhangzhao"
        # ret = models.Publisher.objects.filter(id=1).values("zhangzhao__title")
        # print(ret)
    
    
        # 多对多操作
        # 1. create
        # 做了两件事情:
        # 1. 创建了一个新的作者,2. 将新创建的作者和第一本书做关联
        # ret = models.Book.objects.first().author.create(
        #     name="张曌",
        #     age=16,
        #     phone="18012575998",
        #     detail_id=4
        # )
        # ret = models.Book.objects.first().author.all().values("id")
        # print(ret)
    
        # 2. set
        # models.Book.objects.first().author.set([2,3])
        # ret = models.Book.objects.first().author.all().values("id")
        # print(ret)
    
        # 3. add
        # models.Book.objects.first().author.add(1)
    
        # ret = models.Book.objects.first().author.all().values("id")
        # print(ret)
    
        # 4. remove
        # models.Book.objects.first().author.remove(3)
    
        # ret = models.Book.objects.first().author.all().values("id")
        # print(ret)
    
        # 5.clear
        # models.Book.objects.first().author.clear()
        #
        # ret = models.Book.objects.first().author.all().values("id")
        # print(ret)
    
        # 6. all
        # ret = models.Book.objects.first().author.all()
        # print(ret)
    
        # 聚合
        # 查询所有书的总价格
        from django.db.models import Avg, Sum, Max, Min, Count
        #
        # ret = models.Book.objects.aggregate(total_price=Sum("price"))
        # print(ret)
        #
        # ret = models.Book.objects.aggregate(avg_price=Avg("price"), max_price=Max("price"), min_price=Min("price"))
        # print(ret)
    
        # 求每一本书的作者个数
        # ret = models.Book.objects.annotate(c=Count("author")).values("title", "c")
        # print(ret)
    
        # 统计出每个出版社买的最便宜的书的价格
        # ret = models.Publisher.objects.annotate(min_price=Min("books__price")).values("name", "min_price")
        # print(ret)
    
        # 统计不止一个作者的图书 (书作者的数量大于1)
        # ret = models.Book.objects.annotate(c=Count("author")).filter(c__gt=1)
        # print(ret)
    
        # 按照书作者的数量做排序
        # ret = models.Book.objects.annotate(c=Count("author")).order_by("c")
        # print(ret)
    
        # 查询各个作者出的书的总价格
    
        # ret = models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
        # print(ret)
    View Code

     

    sql联表

     

     

  • 相关阅读:
    状态压缩 + 暴力 HDOJ 4770 Lights Against Dudely
    简单几何(推公式) UVA 11646 Athletics Track
    简单几何(四边形形状) UVA 11800 Determine the Shape
    简单几何(求交点) UVA 11437 Triangle Fun
    计算几何模板
    简单几何(相对运动距离最值) UVA 11796 Dog Distance
    简单几何(求划分区域) LA 3263 That Nice Euler Circuit
    覆盖的面积 HDU
    Desert King 最小比率生成树 (好题)
    约会安排 (区间合并)毒瘤题
  • 原文地址:https://www.cnblogs.com/maojiang/p/9209444.html
Copyright © 2020-2023  润新知