首页 > 解决方案 > 更高效的 Django (SQL) 查询

问题描述

在一个 Django 项目上工作,我有一个用户和艺术品数据库,后者可以被喜欢。我想查询,以获取单个用户对他们所有图片的点赞数。我可以在views.py 中编写两个for 循环,但这很慢。我也把它写成一个单独的(可怕的)SQL查询,但我不确定如何正确使用它,因为它不再是一个查询集(我想我必须以我获取所有必需的数据?)。

最终的想法是简单地创建一个包含用户、他们的电子邮件、他们的图片收到的赞数以及发布的图片数量的表格。以下是相关模型(我使用默认的 Django auth_user 用户表)和 SQL 查询。

class Arts(models.Model):
user_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, unique=False)
title = models.CharField(max_length=100)
description = models.TextField(unique=False, null=False, blank=True)
timestamp = models.DateTimeField(default=timezone.now)
url = models.URLField()
likes = models.IntegerField(default=0)

用户喜欢的艺术品

class Like(models.Model):                                  
artwork = models.ForeignKey(Arts, on_delete=models.CASCADE)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

我的views.py for循环:

def all_users(request):
...
liked = defaultdict()
for user in users_all:
    liked[user.id] = 0
    for artwork in Arts.objects.filter(user_id=user.id):
        liked[user.id] += artwork.likes
...

SQL查询

    with connection.cursor() as cursor:
    sql = """
WITH lajki AS 
(SELECT user_id_id, likes FROM artists_arts ORDER BY likes) 
SELECT user_id_id, SUM(likes) AS suma 
FROM lajki 
GROUP BY user_id_id 
ORDER BY suma DESC
"""
    cursor.execute(sql)
    def namedtuplefetchall(cursor):
        desc = cursor.description
        nt_result = namedtuple('Result', [col[0] for col in desc])
        return [nt_result(*row) for row in cursor.fetchall()]
    liked = namedtuplefetchall(cursor)

有没有办法更有效地做到这一点?

标签: pythonsqldjango

解决方案


根本不需要使用原始查询。您可以通过以下方式查询:

从 django.contrib.auth 导入 get_user_model

def all_users(request):
    users = get_user_model().objects.annotate(
        suma=Sum('arts__likes')
    ).order_by('-suma')
    # …

从此查询集中产生的用户对象将具有一个额外的属性,该属性将对该用户的相关对象.suma求和。这通常会避免使用临时表,而只需进行一次查询。likesArts

但是,我不确定将 存储likesArts对象中是否是个好主意。这基本上是数据复制(您将聚合形式的数据存储在对象中)。事实证明,即使在同一个数据库上,保持数据同步也更加困难。因此,按对象计算Arts对象的喜欢可能会更好Like


推荐阅读