首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在另一个方法中使用/调用具有计算查询集的方法是否多次访问数据库?

在另一个方法中使用/调用具有计算查询集的方法是否多次访问数据库?
EN

Stack Overflow用户
提问于 2022-04-03 04:37:05
回答 1查看 21关注 0票数 0

我正在从事一个DRF项目,以了解ContentType模型。我创建了一个post模型和注释模型(ContentType),然后将评论添加到文章中。在我添加django-调试工具和重复查询之前,一切都很好。

我有以下问题:

  1. 我在注释模型上定义了一个方法(子)和属性(Total_replies)。因为total_replies只是调用子方法并计算queryset的大小。如果我在其他方法或属性中使用子方法,它会导致访问数据库两次或更多次吗?
  2. 如果数据库多次命中,什么解决方案二可以提高性能?
  3. 在添加select_related之后,查询的num大大减少了。在使用select_related之前

使用select_related后

在所有使用Foreignkey的地方使用select_related好吗?

博客应用程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
models.py

class Post(models.Model):
    title = models.CharField(verbose_name=_("Post Title"), max_length=50)
    content = models.TextField()
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='blog_posts')
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    @property
    def comments(self):
        instance = self
        #qs = Comment.objects.filter_by_instance(instance) #before
        qs = Comment.objects.select_related('user').filter_by_instance(instance)
        return qs

    @property
    def get_content_type(self):
        instance = self
        content_type = ContentType.objects.get_for_model(instance.__class__)
        return content_type


serializers.py
class PostSerializer(serializers.ModelSerializer):
    author = UserPublicSerializer(read_only=True)
    status_description = serializers.ReadOnlyField(source='get_status_display')

    class Meta:
        model = Post
        fields = (
            'url', 'id', 'title', 'author',
            'content', 'category', 'total_likes',
        )


class PostDetailSerializer(serializers.ModelSerializer):
    author = UserPublicSerializer(read_only=True)
    status_description = serializers.ReadOnlyField(source='get_status_display')
    comments = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = (
            'url', 'id', 'title', 'author', 'content',
            'category', 'comments', 'total_likes'
        )


    def get_comments(self, obj):
        request = self.context.get('request')
        comments_qs = Comment.objects.filter_by_instance(obj)
        comments = CommentSerializer(comments_qs, many=True, context={'request':request}).data
        return comments


class PostListCreateAPIView(generics.ListCreateAPIView):
    serializer_class = serializers.PostSerializer
    # queryset = Post.objects.all().order_by('-id') # before
    queryset = Post.objects.select_related('author').order_by('-id')
    name = 'post-list'
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

class PostRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = serializers.PostDetailSerializer
    # queryset = Post.objects.all().order_by('-id') # before
    queryset = Post.objects.select_related('author').order_by('-id')
    name = 'post-detail'
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, account_permissions.IsStaffOrAuthorOrReadOnly]

    def perform_update(self, serializer):
        serializer.save(author=self.request.user)

评论应用程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
models.py

class CommentManager(models.Manager):
    def all(self):
        qs = super().filter(parent=None)
        return qs

    def filter_by_instance(self, instance):
        content_type = ContentType.objects.get_for_model(instance.__class__)
        object_id = instance.id
        qs = super().filter(content_type=content_type, object_id=object_id).select_related('user').filter(parent=None)
        return qs


class Comment(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='comments')
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey(ct_field='content_type', fk_field='object_id')
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
    content = models.TextField()
   
    objects = CommentManager()

    def __str__(self):
        if self.is_parent:
            return f"comment {self.id} by {self.user}"
        return f"reply {self.id} to comment {self.parent.id} by {self.user}"

    def children(self):
        return Comment.objects.select_related('user').filter(parent=self)

    @property
    def is_parent(self):
        if self.parent is not None:
            return False
        return True

    @property
    def total_replies(self):
        return self.children().count()


serializers.py

class CommentSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='comment-detail', lookup_field='pk')
    user = UserPublicSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('url', 'user', 'id', 'content_type', 'object_id', 'parent', 'content',  'total_replies',)


class CommentChildSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='comment-detail', lookup_field='pk')
    user = UserPublicSerializer(read_only=True)

    class Meta:
        model = Comment
        fields = ('url', 'user',  'id', 'content',)


class CommentDetailSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='comment-detail', lookup_field='pk')
    replies = serializers.SerializerMethodField()

    class Meta:
        model = Comment
        fields = ('url', 'id', 'content_type', 'object_id', 'content', 'replies', 'total_replies',)

    def get_replies(self, obj):
        request = self.context.get('request')
        if obj.is_parent:
            return CommentChildSerializer(obj.children(), many=True, context={'request':request}).data
        return None


views.py

class CommentListAPIView(generics.ListCreateAPIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = Comment.objects.select_related('user').order_by('-id')
    name = 'comment-list'
    serializer_class = serializers.CommentSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

class CommentDetailAPIView(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = Comment.objects.select_related('user').all()
    name = 'comment-detail'
    serializer_class = serializers.CommentDetailSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

提前谢谢。

EN

回答 1

Stack Overflow用户

发布于 2022-04-03 06:10:40

django博士正是这么说相关的:

返回一个将“跟踪”外键关系的QuerySet,在执行其查询时选择附加的相关对象数据。--这是一个性能提升器,会产生一个更复杂的查询,但意味着以后使用外键关系将不需要数据库查询。

他们将select_related描述为复杂但在事务性数据库成本方面很好的东西。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71725965

复制
相关文章
Array和ArrayList的不同点
本文最后更新于 848 天前,其中的信息可能已经有所发展或是发生改变。 Array和ArrayList的不同点 Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。 Array大小是固定的,ArrayList的大小是动态变化的。 ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。 Post Views:
Yuyy
2022/06/28
1610
arraylist遍历 并删除_js遍历list对象
//第一种遍历 ArrayList 对象的方法 foreach(object o in al) { Console.Write(o.ToString()+” “); }
全栈程序员站长
2022/11/10
7.5K0
JavaScript中数组遍历方法array.some()的应用,数组遍历操作的方法
        因为它简单,好用,清晰,可拓展性强,而且比for、foreach还有非常不常用的while、do...while高级,代码清晰,可读性强,代码就看起来很优雅,如果都是嵌套循环和嵌套回调,看起来就是一团乱麻,可读性差,很不优雅。
watermelo37
2025/01/22
5000
Array 与 NSArray 的不同点对比表
是什么(类型) 可变吗 能存啥 NSArray 引用类型,不同指针变量指向同一块内存,对一个变量操作时,会自动映射到另一个变量。 创建后,不可变 单个数组对象,可存 OC 语言环境下的多种对象数据类型,eg:@[@1, "2", 对象] Array 值类型,每个变量有自己的数据拷贝。对一个变量的操作不会影响其他变量。 声明为var时可变,声明为let时不可变 单个对象,只能存储同类型任意类型元素,eg:[1,2,3],["1", "2", "3"]
woopDast1
2021/10/20
5370
JavaScript 学习-4.Array数组遍历的几种方式
前言 Array 数组遍历的几种方式 普通for循环 循环遍历基础语法 for(var i = 0; i < arr.length; i++){ ... } 使用示例 var arr1 = ['hello', 'world', 'aa']; for (var i=0; i<arr1.length; i++){ console.log(i) // 下标 console.log(arr1[i]) // 成员 } 运行结果 for…in for...in 循环的是数组下标,语
上海-悠悠
2022/05/16
9810
JavaScript 学习-4.Array数组遍历的几种方式
IDS入侵检测系统的缺点_IDS入侵检测是指依照
IDS(intrusion detection system)入侵检测系统是一种对网络传输进行即时监视,在发现可疑传输时发出警报或者采取主动反应措施的网络安全设备。它与其他网络安全设备的不同之处便在于,IDS是一种积极主动的安全防护技术。在很多中大型企业,政府机构,都会布有IDS。我们做一个比喻——假如防火墙是一幢大厦的门锁,那么IDS就是这幢大厦里的监视系统。一旦小偷进入了大厦,或内部人员有越界行为,只有实时监视系统才能发现情况并发出警告。
全栈程序员站长
2022/11/07
3.9K0
IDS与IPS的区别
1. ***检测系统(IDS)   IDS是英文“Intrusion Detection Systems”的缩写,中文意思是“***检测系统”。专业上讲就是依照一定的安全策略,对网络、系统的运行状况进行监视,尽可能发现各种***企图、***行为或者***结果,以保证网络系统资源的机密性、完整性和可用性。
孙杰
2019/10/29
2.7K0
IDS与IPS的区别
Array.slice 8种不同用法
随着React和其他面向功能的JavaScript实践的兴起,它变得越来越重要,原因有两个:
Javanx
2019/09/30
7800
Array.slice 8种不同用法
随着React和其他面向功能的JavaScript实践的兴起,它变得越来越重要,原因有两个:
前端小智@大迁世界
2019/07/10
1.3K0
动态规划:删除并获得点数
从题目中可以获取到的条件是,如果选择了i位置,那么就必须删除与i-1和i+1的位置的值相同的所有的值。
二肥是只大懒蓝猫
2023/10/13
1400
动态规划:删除并获得点数
android 资源文字ids的作用
ids.xml——为应用的相关资源提供唯一的资源id。id是为了获得xml中的对象而需要的参数,也就是Object = findViewById(R.id.id_name)中的id_name。这些值可以在代码中用android.R.id引用到。若在ids.xml中定... ids.xml——为应用的相关资源提供唯一的资源id。id是为了获得xml中的对象而需要的参数,也就是Object = findViewById(R.id.id_name)中的id_name。这些值可以在代码中用android.R.id引
xiangzhihong
2018/02/01
1.7K0
[JavaScript] JS 获取所有相同class的div,并遍历
Again,这个问题对于使用mvvm框架,例如vue,weex和angular 是任何难度的因为他们的dom都是直接用js生成控制的,在生成之初就直接处理好久好了。
用户2353021
2020/05/11
14K0
基于主机的入侵系统IDS
那它如何实现呢:AIDE通过扫面一台为被篡改的linux服务器的文件系统来构建文件属性数据库
星哥玩云
2022/07/03
1.1K0
获得时间并做成字符串
随便贴点代码,以后没准有用 点击(此处)折叠或打开 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/time.h> #include <unistd.h> char *get_time_for_uuid(char *time_string) {         time_t timep;         struct tm *p;
用户3765803
2019/03/05
5630
linux 日期遍历并执行脚本
date +%s  //从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数(时间戳)
week
2022/11/26
1.1K0
python遍历所有窗体并打印标题
//pip install pywin32 def foo(hwnd,mouse):
用户5760343
2022/05/14
7030
ArcGIS创建渔网并批量获得指定大小的网格矢量
  本文介绍在ArcMap软件中,通过“Create Fishnet”工具创建渔网,从而获得指定大小的矢量格网数据的方法。
疯狂学习GIS
2023/10/24
6300
ArcGIS创建渔网并批量获得指定大小的网格矢量
未公开函数 NtQuerySystemInfoMation 遍历进程信息,获得进程的用户名
目录 遍历进程用户名 代码例子 遍历进程用户名 代码例子 #include <windows.h> #include <iostream> #include <COMDEF.H> #include <stdio.h> #include <Tlhelp32.h> using namespace std; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; }
IBinary
2019/05/25
1.4K0
DP-LeetCode-740. 删除并获得点数
思路 有限制的选择问题 选择i就要删除所有的i-1和i+1 讨论当前状态i (1)如果选择了i,则i+1不能选 (2)如果不选择i,则i+1可以选也可以不选 状态表示: f[i][0]表示只考虑前i个数,不选择i所有选法中所能得到的最大值; f[i][1]表示只考虑前i个数,选择i所有选法中所能得到的最大值; 状态计算: 如果当前i不选,则考虑前i-1个数所能获得的最大值。这时有需要考虑选择不选i-1,如果选择i-1则前i-1个数所能获得的最大值就是f[i-1][1];如果不选择i-1则前i-1个数所
lexingsen
2022/02/24
1420
动态规划 —— dp 问题-删除并获得点数
https://leetcode.cn/problems/delete-and-earn/description/
迷迭所归处
2024/11/19
710
动态规划 —— dp 问题-删除并获得点数

相似问题

在调试器中获得404的例子是for /wp/Array?

10

如何获得不同的相关职位

10

在wordpress中,如何在单击不同的电子邮件ids时依次发送不同的电子邮件

10

如何获得带有关联类别和标记名称的post,而不是使用rest的ids?

10

如何遍历所有帖子并使用Get媒体附件计数附件

10
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文