Подтвердить что ты не робот

Обновление Django - save() на дубликат ключа

У меня мало приложений, которые позволяют пользователю оценивать видео.

Пользователь может оценивать только один раз. Поэтому я определил уникальность модели.

Но он должен быть в состоянии изменить свою ставку. Таким образом, save() должен обновлять дублированный ключ

class VideoRate(models.Model):
  """Users can Rate each Video on the criterias defined for the topic"""
  user = models.ForeignKey(User)
  video = models.ForeignKey(VideoFile)
  crit = models.ForeignKey(VideoCrit)
  rate = models.DecimalField(max_digits=2, decimal_places=1, choices=RATE_CHOICES)
  class Meta:
    unique_together = (('user', 'video', 'crit'),)
    verbose_name = 'Video Rating'

Если I

rate = VideoRate(user_id=1, video_id=1, crit_id=1, rate=2)
rate.save()

Сохраняет рейтинг, но если я

rate = VideoRate(user_id=1, video_id=1, crit_id=1, rate=3)
rate.save()

Я получаю нормальную ошибку

IntegrityError: (1062, "Duplicate entry '1-1-1' for key 'user_id'")

Даже если я использую force_update=True (поскольку он основан только на первичных ключах)

Есть ли способ обновить рейтинг, если он уже существует без проверки данных раньше?

4b9b3361

Ответ 1

Чтобы обновить существующий рейтинг, вы действительно должны иметь тот, который хотите обновить. Если вы знаете, что объект может не существовать, используйте get_or_create:

rate, created = VideoRate.objects.get_or_create(user_id=1, video_id=1, crit_id=1)
rate.rate = 2
rate.save()

Вы можете сократить процесс, используя update():

VideoRate.objects.filter(user_id=1, video_id=1, crit_id=1).update(rate=2)

Но это будет терпеть неудачу, если рейтинг не существует - он не создаст его.

Ответ 2

Во-первых, вы должны проверить, существует ли рейтинг. Поэтому вы можете использовать то, что сказал Daniel Roseman, или использовать существует, но вы не можете решить это с помощью простого обновления, так как обновление не создает новые записи...

rating = 2
rate, created = VideoRate.objects.get_or_create(user_id=1, video_id=1, crit_id=1,
    defaults={'rate':rating})#if create, also save the rate infdormation

if not created:# update
    rate.rate = rating
    rate.save()

Вы можете использовать defaults, чтобы передавать аргументы exrta, поэтому, если это вставить, запись базы данных будет создана со всей необходимой информацией, и вам не нужно ее обновлять снова...

Документация

Обновление: Этот ответ довольно старый, как вопрос. Как упоминает @peterthomassen, у Django теперь update_or_create() method