【问题标题】:A more efficient Django (SQL) query更高效的 Django (SQL) 查询
【发布时间】:2020-08-28 22:15:06
【问题描述】:

在一个 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)

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

【问题讨论】:

    标签: python sql django


    【解决方案1】:

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

    从 django.contrib.auth 导入 get_user_model

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

    由此查询集产生的用户对象将具有一个额外的属性.suma,它将对该用户的相关Arts 对象的likes 求和。这通常会避开临时表,只进行一次查询。

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

    【讨论】:

    • .annotate 正是我想要的。我认为有一种将这两个模型分组的好方法,但就是想不通。非常感谢。至于对艺术的喜爱,是的,我们注意到当我们在处理表格时,但到那时我们只是保持原样。不过会尝试修复它。
    猜你喜欢
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多