Reputation: 23
Is there a way to make model fields unique with other models referencing the same ForeignKey?
In my case I am trying to make it so that the names
of Attribute
models with the same Obj
are unique. Ex: if there exists a CharAttribute
with name='Types'
and obj=1
there can't be another CharAttribute
with name='Types'
and obj=1
nor an IntAttribute
with name='Types'
and obj=1
class Obj (models.Model):
name = models.CharField(max_length=40)
class CharAttribute (models.Model):
name = models.CharField(max_length=40)
obj = models.ForeignKey(Obj, on_delete=models.CASCADE)
class IntAttribute (models.Model):
name = models.CharField(max_length=40)
obj = models.ForeignKey(Obj, on_delete=models.CASCADE)
My current idea for a solution would be something like this:
def clean_fields(self, exclude=None):
super().clean_fields(exclude=exclude)
for other_name in IntAttribute.objects.filter(obj=self.obj):
if self.name == other_name:
raise ValidationError(
('Attributes of the same object may not have the same name, %(name) s already exists for '
'%(object) s' % {'name': self.name, 'object': self.obj.name})
)
for other_name in CharAttribute.objects.filter(obj=self.obj):
if self.name == other_name:
raise ValidationError(
('Attributes of the same object may not have the same name, %(name) s already exists for '
'%(object) s' % {'name': self.name, "object": self.obj.name})
)
But creating another for loop for each possible future created Attribute
feels repetitive and there must be a better way of accomplishing this task.
Thank you in advance for the feedback.
Upvotes: 0
Views: 36
Reputation: 1810
You can use unique_together to make sure no combination of fields is repeated in a model:
class CharAttribute (models.Model):
name = models.CharField(max_length=40)
obj = models.ForeignKey(Obj, on_delete=models.CASCADE)
class Meta:
unique_together = ('name', 'obj')
Between models you would have to do a manual validation:
class CharAttribute (models.Model):
name = models.CharField(max_length=40)
obj = models.ForeignKey(Obj, on_delete=models.CASCADE)
class Meta:
unique_together = ('name', 'obj')
def clean(self):
if IntAttribute.objects.filter(name=self.name, obj=self.obj).exists():
raise ValidationError('...')
The same method applies for the other model.
Upvotes: 1