简体   繁体   English

如何在django中更新queryset值?

[英]How to update queryset value in django?

I have written a python script in my project. 我在我的项目中编写了一个python脚本。 I want to update the value of a field. 我想更新字段的值。

Here are my modes 这是我的模式


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"]

This is my python script: 这是我的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()

After counting the total_rate from the Count table I want to update the total star value in News_Channel table. 从Count表中计算total_rate后,我想更新News_Channel表中的总星值。 I am failing to do so and get the data before the update and after the update as zero. 我没有这样做,并在更新之前和更新之后获取数据为零。 Although total_rate has value. 虽然total_rate有价值。

The problem 问题

The reason why this fails is because here object is a QuerySet of News_Channel s, yeah that QuerySet might contain exactly one News_Channel , but that is irrelevant. 为什么失败的原因是因为这里object是一个QuerySetNews_Channel S,是啊是QuerySet可能只包含一个News_Channel ,但是这是无关紧要的。

If you then use object[0] you make a query to the database to fetch the first element and deserialize it into a News_Channel object. 如果然后使用object[0] ,则向数据库进行查询以获取第一个元素并将其反序列化为News_Channel对象。 Then you set the total_star of that object, but you never save that object. 然后设置该对象的total_star ,但永远不保存该对象。 You only call .update() on the entire queryset, resulting in another independent query. 您只在整个查询集上调用.update() ,从而产生另一个独立查询。

You can fix this with: 你可以解决这个问题:

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

Or given you do not need any validation, you can boost performance with: 或者,鉴于您不需要任何验证,您可以通过以下方式提高性能:

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

Updating all News_Channel s 更新所有 News_Channel

If you want to update all News_Channel s, you actually better use a Subquery here: 如果要更新所有 News_Channel ,实际上最好使用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)

The reason is that object in your case is a queryset, and after you attempt to update object[0] , you don't store the results in the db, and don't refresh the queryset. 原因是您的情况下的object是一个查询集,在您尝试更新object[0] ,您不会将结果存储在数据库中,也不会刷新查询集。 To get it to work you should pass the field you want to update into the update method. 要使其工作,您应该将要更新的字段传递给更新方法。

So, try this: 所以,试试这个:

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)

News_Channel.total_star can be calculated by using aggregation 可以使用聚合来计算News_Channel.total_star

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

You can then either use this in your script: 然后,您可以在脚本中使用它:

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

Or if you do not need to cache this value because performance is not an issue, you can remove the total_star field and add it as a property on the News_Channel model 或者,如果您不需要缓存此值,因为性能不是问题,您可以删除total_star字段并将其添加为News_Channel模型上的属性

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM