There are similar issues on SO, but none alike this.
I would like to update a field in a record of a m2m model which has a unique constraint on attendee
+ training
. This model is defined as (model.py
):
class Occurrence(models.Model):
attendee = models.ForeignKey(Attendee, on_delete=models.CASCADE)
training = models.ForeignKey(Training, on_delete=models.CASCADE)
attended_date = models.DateField(default=date(1900, 12, 31))
class Meta:
constraints = [
models.UniqueConstraint(fields=['attendee', 'training'], name='unique_attendee_training')
]
Now, consider e.g. that John has taken the Python course and already exists as record in the db. If I try get the date of when the training occurred, I would go like this:
from trainings.models import Attendee, Training, Occurrence
from datetime import date, datetime
attendee = Attendee.objects.get(pk='john@gmail.com')
training = Training.objects.get(pk='python310')
occurrence = Occurrence.objects.get(attendee=attendee, training=training)
print(occurrence.attended_date)
# datetime.date(2021, 11, 4)
However, if I try to update the date of this record, I get the error.
occurrence = Occurrence(attendee=attendee, training=training, attended_date=date(2021, 11, 5))
occurrence.save(update_fields=["attendee", "training", "attended_date"])
The error being:
ValueError: Cannot force an update in save() with no primary key.
How do I update this record?
Note
I believe this should be enough to understand the question. But if you want to reproduce the whole issue, I post here the models (model.py
) for Attendees and Trainings.
class Attendee(models.Model):
first_name = models.CharField('First Name', max_length=30, blank=False)
last_name = models.CharField('Last Name', max_length=30, blank=False)
email = models.EmailField("Email Address", max_length=75, blank=False, primary_key=True)
Using email
as pk.
class Training(models.Model):
long_name = models.CharField('Training Name', max_length=80, blank=False, null=False)
short_name = models.CharField('Abbreviation', max_length=10, blank=False, null=False, primary_key=True)
description = models.TextField('Descriprion', blank=True)
alumni = models.ManyToManyField(Attendee, through='Occurrence')
Using short_name
as pk. With alumni
that relates Attendee
and Occurrence
.
>Solution :
You are updating the record in the wrong way,
occurrence = Occurrence.objects.get(attendee=attendee, training=training)
print(occurrence.attended_date) # # datetime.date(2021, 11, 4)
# update the record like this
occurrence.attended_date = date(2021, 11, 5)
occurrence.save()
You can tell Django to update specific fields by passing the update_fields
parameter, as
# Use instead of `occurrence.save()`
occurrence.save(update_fields=["attended_date"])