如何在Django中更新查询集(queryset)的值?

4

我在我的项目中编写了一个Python脚本,我想要更新字段的值。

以下是我的模式:


class News_Channel(models.Model):
    name = models.TextField(blank=False)
    info = models.TextField(blank=False)
    image = models.FileField()
    website = models.TextField()
    total_star = models.PositiveIntegerField(default=0)
    total_user = models.IntegerField()

    class Meta:
        ordering = ["-id"]

    def __str__(self):
        return self.name

class Count(models.Model):
    userId = models.ForeignKey(User, on_delete=models.CASCADE)
    channelId = models.ForeignKey(News_Channel, on_delete=models.CASCADE)
    rate = models.PositiveIntegerField(default=0)

    def __str__(self):
        return self.channelId.name

    class Meta:
        ordering = ["-id"]

这是我的Python脚本:

from feed.models import Count, News_Channel


def run():
    for i in range(1, 11):
        news_channel = Count.objects.filter(channelId=i)
        total_rate = 0
        for rate in news_channel:
            total_rate += rate.rate
        print(total_rate)
        object = News_Channel.objects.filter(id=i)
        print(total_rate)
        print("before",object[0].total_star,total_rate)
        object[0].total_star = total_rate
        print("after", object[0].total_star)
        object.update()


在计算“Count表”的total_rate后,我想更新“News_Channel表”中的总星级值。但是我无法成功地执行此操作,并且在更新之前和之后获取到的数据均为零。尽管total_rate有值。
3个回答

12

问题

这个失败的原因是因为这里的object是一个News_ChannelQuerySet,没错,这个QuerySet可能只包含一个News_Channel,但这并不重要。

如果你使用object[0]来获取第一个元素并将其反序列化为一个News_Channel对象,然后设置该对象的total_star,但是你从未保存该对象。你只对整个查询集合调用.update(),导致另一个独立的查询。

你可以通过以下方式解决这个问题:

objects = News_Channel.objects.filter(id=i)
<b>object = objects[0]</b>
object.total_star = total_rate
object<b>.save()</b>

如果您不需要任何验证,您可以通过以下方式提高性能:

News_Channel.objects.filter(id=i).update(total_star=total_rate)

更新所有新闻频道

如果您想要更新所有的新闻频道,最好使用一个子查询:

from django.db.models import OuterRef, Sum, Subquery

subq = Subquery(
    Count.objects.filter(
        channelId=OuterRef('id')
    ).annotate(
        total_rate=Sum('rate')
    ).order_by('channelId').values('total_rate')[:1]
)

News_Channel.objects.update(total_star=subq)

6
原因是在您的情况下,object是一个 queryset,而在尝试更新 object[0] 后,您没有将结果存储在数据库中,也没有刷新 queryset。要使其正常工作,您应该将要更新的字段传递给 update 方法。

所以,请尝试这样做:

def run():
    for i in range(1, 11):
        news_channel = Count.objects.filter(channelId=i)
        total_rate = 0
        for rate in news_channel:
            total_rate += rate.rate
        print(total_rate)
        object = News_Channel.objects.filter(id=i)
        print(total_rate)
        print("before",object[0].total_star,total_rate)
        object.update(total_star=total_rate)
        print("after", object[0].total_star)

2

News_Channel.total_star可以通过使用聚合来计算。


news_channel_obj.count_set.aggregate(total_star=Sum('rate'))['total_star']

你可以在脚本中使用以下内容:

最初的回答

object.total_star = object.count_set.aggregate(total_star=Sum('rate'))['total_star']

如果性能不是问题,您可以删除total_star字段,并将其添加为News_Channel模型的属性,这样就不需要缓存该值。

最初的回答:

或者,如果您不需要缓存此值,因为性能不是问题,您可以删除total_star字段,并将其作为News_Channel模型的属性添加。

@property
def total_star(self):
    return self.count_set.aggregate(total_star=Sum('rate'))['total_star']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接