Make save method atomic

This commit is contained in:
Oliver Walters 2026-06-13 11:08:13 +00:00
parent 5b18401684
commit fdef49c25e
2 changed files with 27 additions and 7 deletions

View File

@ -121,4 +121,13 @@ class Migration(migrations.Migration):
related_name='images',
),
),
# Add constraint to ensure that only one 'primary' note exists per model instance
migrations.AddConstraint(
model_name="note",
constraint=models.UniqueConstraint(
condition=models.Q(("primary", True)),
fields=("model_type", "model_id"),
name="unique_primary_note_per_model",
),
),
]

View File

@ -3000,21 +3000,34 @@ class Note(
verbose_name = _('Note')
verbose_name_plural = _('Notes')
constraints = [
models.UniqueConstraint(
fields=['model_type', 'model_id'],
condition=models.Q(primary=True),
name='unique_primary_note_per_model',
)
]
@staticmethod
def get_api_url() -> str:
"""Return the API URL associated with the Parameter model."""
return reverse('api-note-list')
@transaction.atomic
def save(self, *args, **kwargs):
"""Perform custom save checks before saving a Note instance."""
self.check_save()
others = Note.objects.filter(
model_type=self.model_type, model_id=self.model_id
).exclude(pk=self.pk)
# Lock sibling notes to serialize concurrent primary-flag updates
siblings = (
Note.objects
.select_for_update()
.filter(model_type=self.model_type, model_id=self.model_id)
.exclude(pk=self.pk)
)
# If this is the *only* note for this model instance, then set it as the primary note
if not others.exists():
if not siblings.exists():
self.primary = True
self.clean()
@ -3023,9 +3036,7 @@ class Note(
# Once this note is saved, mark other notes as non-primary
if self.primary:
Note.objects.filter(
model_type=self.model_type, model_id=self.model_id
).exclude(pk=self.pk).update(primary=False)
siblings.update(primary=False)
self.cleanup_images()