Я написал скрипт 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"]
Это мой скрипт на питоне:
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()
После подсчета total_rate из таблицы Count я хочу обновить общее значение звезды в таблице News_Channel. Я не могу этого сделать и получить данные до обновления и после обновления как ноль. Хотя total_rate имеет значение.
Причина в том, что object
в вашем случае — это набор запросов, и после того, как вы попытаетесь обновить object[0]
, вы не сохраните результаты в БД и не обновите набор запросов. Чтобы заставить его работать, вы должны передать поле, которое хотите обновить, в метод обновления.
Итак, попробуйте следующее:
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)
Причина, по которой это не удается, заключается в том, что здесь object
— это QuerySet
из News_Channel
s, да, 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_Channel
sЕсли вы хотите обновить всеNews_Channel
s, вам лучше использовать 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)
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
.
@property
def total_star(self):
return self.count_set.aggregate(total_star=Sum('rate'))['total_star']