TL;DR: How do you save/validate multiple objects with a unique attribute using a formset?
Let's say I have a Machine which has multiple Settings (see models below). These settings should have a unique ordering within the machine. This can be accomplished by defining a unique_together attribute in the Meta class of the Setting model:
unique_together = (('order', 'machine'), )
However, I'm using an inline formset to update all the Settings of a Machine. Assume I have the following info in my formset:
- Setting 1: machine=1; order=1
- Setting 2: machine=1; order=2
If I were to switch the order on the two Settings:
- Setting 1: machine=1; order=2
- Setting 2: machine=1; order=1
and save the form using the following piece of code:
self.object = machine_form.save()
settings = setting_formset.save(commit=False)
for setting in settings:
setting.machine = self.object
setting.save()
Then I get a Unique Constraint Error since I'm trying to save Setting 1 with order=2, but Setting 2 still has that order. I can't seem to find a clean solution for this problem. I would like to keep the unique_together constraint to ensure the correctness of my data. I know how to solve this in the frontend using Javascript, but I want a check in my models/forms. Looping over the formset rows seems possible, but ugly?
class Machine(models.Model):
name = models.CharField(max_length=255)
class Setting(models.Model):
name = models.CharField(max_length=255)
machine = models.ForeignKey(Machine, on_delete=models.CASCADE)
order = models.PositiveSmallIntegerField()