• bbs项目中对反向查询和分组查询的具体的应用


    我的数据库是按照下面的图片的方式设计的

    然后看下model中代码

    class User(models.Model):
        uid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32,unique=True)
        def __str__(self):
            return self.username
        class Meta:
            verbose_name = "博客用户表"
            verbose_name_plural = verbose_name
    
    class Blog(models.Model):
        bid = models.AutoField(primary_key=True)
        blog_title = models.CharField(max_length=32,verbose_name="博客标题")
        blog_site = models.OneToOneField(to="User",to_field="uid",verbose_name="博客网址",on_delete=True)
    
        def __str__(self):
            return self.blog_title
        class Meta:
            verbose_name = "博客表"
            verbose_name_plural = verbose_name
    
    class Article(models.Model):
        aid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=50, verbose_name="文章标题")  # 文章标题
        desc = models.CharField(max_length=255)  # 文章描述
        create_time = models.DateTimeField()
        category = models.ForeignKey(to="Category", to_field="cid", null=True,on_delete=True)
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name = "文章表"
            verbose_name_plural = verbose_name
    
    
    
    class Category(models.Model):
        cid = models.AutoField(primary_key=True)
        category_title = models.CharField(max_length=32)  # 分类标题
        blog = models.ForeignKey(to="Blog", to_field="bid",on_delete=True)  # 外键关联博客,一个博客站点可以有多个分类
    
        def __str__(self):
            return self.category_title
    
        class Meta:
            verbose_name = "文章分类"
            verbose_name_plural = verbose_name
    
    class Tag(models.Model):
        tid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=64,default="xxx")
        tag_title = models.ManyToManyField(to="Article",)
        tag_blog = models.ForeignKey(to="Blog", to_field="bid",on_delete=True)  # 所属博客
    
        def __str__(self):
            return self.title
        class Meta:
            verbose_name = "标签表"
            verbose_name_plural = verbose_name
    

    表结构梳理

    a、用户表和博客表是一对一的关系

    b、文章分类表和博客是多对一的关系,即一个博客可以有多个分类

    c、文章标签表和博客是多对一的关系,即一个博客可以有多个标签

    d、文章和分类表是多对一的关系,一个文章只能有一个分类,而一个分类中可以有多个文章

    e、文章和标签表是多对多的关系,一个文件可以有多个标签,而一个标签中可以有多个文章

    现在的场景如下

    一个用户过来访问数据库,比如test1,我们通过用户拿到这个用户对应的blog的对象,通过blog对象拿到这个blog对象的文章分类的对象,然后按照文章分类的id做分组计算,通过跨表查询获取每个分类下的文章

    代码如下

        from app1 import models
        from django.db.models import Count
        # a、通过用户名找到该用户对应的博客的对象
        obj = models.User.objects.filter(username="test1")[0].blog
        print(obj, type(obj))
    
        # 方法1、通过分组聚合的方式
        # b、通过博客找到这个博客的所有的分类,然后按照分类的ip进行分组统计,统计每个分类的下的文章的数量
        # obj = obj.category_set.all().values("cid").annotate(c=Count("article__aid")).values("category_title","c","cid")
        # print(obj)
    
        # 方法2、通过跨表查询的方式
        obj = obj.category_set.all()[0].article_set.all().count()
        print(obj)
    

    同样,如果我们要计算某个人的博客下的每个标签的文章,思路是一样的

        obj = models.User.objects.filter(username="test1")[0].blog
    
        obj = obj.tag_set.all().values("tid").annotate(c=Count("tag_title__aid")).values("title","c")
        print(obj)
    
        obj = models.User.objects.filter(username="test1")[0].blog
    
        obj = obj.tag_set.all()[3].tag_title.count()
        print(obj)
    

    关于反向查询还是有点不清楚,用下面这个例子在来巩固一下

        from app1 import models
        from django.db.models import Count
        # a、通过用户名找到该用户对应的博客的对象
        obj = models.User.objects.filter(username="test1")[0].blog
    
        # 1、通过对象进行反向查询
        category_obj = obj.category_set.all()
        article_obj = category_obj.values("article__title")
        print(article_obj)
    

     

    下面解释一下上面的代码

    obj = models.User.objects.filter(username="test1")[0].blog
    

    a、首先通过用户的名字找到这个用户在User表中的queryset对象
    b、然后通过索引取第一个,拿到一个具体的用户对象
    c、最后,由于blog表和 User表是一对一的关系,但是一对一的字段blog_site字段在blog表中,我们如果想通过User表找到Blog表的对象,就只能通过表名,这里就要注意,虽然我们的表名叫做Blog,但是这里必须要全小写,所以通过.blog拿到这个用户的Blog对象

    category_obj = obj.category_set.all()
    

    a、首先我们在上一段中拿到Blog对象,我们要通过Blog对象拿到这个对象的category信息,由于Blog表和Category是外键的关系,但是外键字段在Category表中,且由于上一步我们拿到的是一个具体的Blog对象,所以可以使用“表名”+"_set"方法去做跨表查询,这里就拿到这个Blog对象对应的Category的queryset对象,然后调用all方法,拿到所有的Category对象

    article_obj = category_obj.values("article__title")
    

    a、上一步我们拿到一个category的queryset对象,然后我们调用values方法去拿到这个category对象对应的文章的标题
    b、由于category和article是外键的关系,且外键字段在article表中,这里如何通过category对象去获取article表的信息呢?这里也可以也要通过“表名”+“__”双下划线去做跨表查询

    这里我们要非常注意,如果是反向查询
    如果是具体的对象,格式为“表名”+"_set"的方式进行跨表查询,切记这里的表名是全小写
    如果是queryset的对象,可以在values中做跨表查询,格式为“表名”+“__”,表名+双下划线的方式做跨表查询,切记这里的表名是全小写

    我们在看下例子

    obj = models.User.objects.filter(username="test1")[0].blog
    category_obj = obj.category_set.all()
    article_obj2 = category_obj[0].article_set.values("title")
    print(article_obj2)
    
    obj = models.User.objects.filter(username="test1")[0].blog
    

    a、同上

    category_obj = obj.category_set.all()
    

    a、同上

    article_obj2 = category_obj[0].article_set.values("title")
    

    a、上一步我们拿到一个分类的queryset对象。然后通过索引取第一个元素,拿到的就是一个具体的分类的对象
    b、由于是具体的对象,我们如果要进行反向查询,则可以使用“表名”+“_set”的方法做反向查询。拿到这个分类对应的文章表对应的所以的文章对象,拿到文章对象后,由于文章对象有和title字段,所以这里就不需要做什么跨表查询,直接可以使用文章表中的字段title进行打印即可

  • 相关阅读:
    实验室 Linux 集群的管理常用命令
    python操作MySQL数据库
    python 文件操作总结
    MySQL常用的操作整理
    机器学习模型数据结构:logistic regression, neural network, convolutional neural network
    Python并发编程之线程池/进程池--concurrent.futures模块
    python3.5实现购物车
    Centos上安装python3.5以上版本
    [Python]关于return逻辑判断和短路逻辑
    [Python]返回函数,装饰器拾遗
  • 原文地址:https://www.cnblogs.com/bainianminguo/p/9876996.html
Copyright © 2020-2023  润新知