Reputation: 1745
Given these two models:
models.py
PRIMARY, SECONDARY = 0, 1
STORAGE_TYPE = (
(PRIMARY, "Primary"),
(SECONDARY, "Secondary"),
)
class Storage(models.Model):
company = models.ForeignKey(Company, related_name='storage')
storage_type = models.PositiveIntegerField(choices=STORAGE_TYPE)
class Company(models.Model):
name = models.CharField(max_length=64)
I want to add a restriction so one Company only may have one Primary storage_type. The rest must be Secondary.
What would be the best way to achieve this?
Is this a good practice?:
models.py
# ... Storage model
def clean(self):
if self.storage_type == PRIMARY:
if self.objects.filter(company=self.company, storage_type=PRIMARY).exists():
raise ValidationError({'storage_type': 'Already exists a Primary storage.'})
Upvotes: 1
Views: 432
Reputation: 53734
Well, this is a good practice if you are on a database that does not support constraints. For example, postgresql can do this sort of check at database level. It's always better to rely on the database for data integrity where ever possible. That's because the sort of check that you are doing in your clean method can lead to race conditions.
If you are on something like mysql (which has only unique and foreign key constraints), you can continue with your current approach. You might also want to consider storing numbers (1,2,3,) in your field so that 1 stands for primary and 2,3,4 etc stands for secondary storages. This way you are able to give them an order of precedence as well. Then:
class Storage(models.Model):
company = models.ForeignKey(Company, related_name='storage')
storage_type = models.PositiveIntegerField(choices=STORAGE_TYPE)
class Meta:
unique_together = ('company','storage')
Upvotes: 1
Reputation: 23
You should accomplish this task in the form save method.
forms.py
class StorageForm(forms.ModelForm):
def clean_company(self):
company = self.cleaned_data.get('company')
if company.storage_set.filter(storage_type=0).exists():
raise forms.ValidationError('your_message')
return company
class Meta:
model = Storage
fields = '__all__'
Upvotes: 0