【问题标题】:How to update queryset value in django?如何更新 django 中的查询集值?
【发布时间】:2019-05-27 21:14:56
【问题描述】:

我在我的项目中编写了一个 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 有价值。

【问题讨论】:

    标签: python django django-models django-queryset


    【解决方案1】:

    问题

    失败的原因是因为这里的objectNews_Channels 中的QuerySet,是的,QuerySet 可能正好包含一个News_Channel,但这无关紧要。

    如果您随后使用object[0],您将查询数据库以获取第一个元素并将其反序列化为News_Channel 对象。然后您设置该对象的total_star,但您从不保存该对象。您只在整个查询集上调用.update(),导致另一个独立查询。

    您可以通过以下方式解决此问题:

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

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

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

    更新全部 News_Channels

    如果你想更新所有 News_Channels,你实际上最好在这里使用Subquery

    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)

    【讨论】:

      【解决方案2】:

      原因是您的object 是一个查询集,在您尝试更新object[0] 后,您不会将结果存储在数据库中,也不会刷新查询集。要让它工作,您应该将要更新的字段传递给 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)
      

      【讨论】:

        【解决方案3】:

        News_Channel.total_star可以用aggregation计算

        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 模型上

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

        【讨论】:

          猜你喜欢
          • 2019-12-10
          • 1970-01-01
          • 1970-01-01
          • 2014-01-02
          • 1970-01-01
          • 2020-02-12
          • 2017-08-12
          • 2015-03-17
          • 2021-10-21
          相关资源
          最近更新 更多