I have a Django model which looks like this:
class MyModel(models.Model): parent = models.ForeignKey(ParentModel) name = models.CharField(blank=True, max_length=200) ... other fields ... class Meta: unique_together = ("name", "parent") This works as expected; If there is the same name more than once in the same parent then I get an error: "MyModel with this Name and Parent already exists."
However, I also get an error when I save more than one MyModel with the same parent but with the name field blank, but this should be allowed. So basically I don't want to get the above error when the name field is blank. Is that possible somehow?
If a string-based field has null=True , that means it has two possible values for “no data”: NULL, and the empty string. In most cases, it's redundant to have two possible values for “no data;” the Django convention is to use the empty string, not NULL.
null=True will set the field's value to NULL i.e., no data. It is basically for the databases column value. blank=True determines whether the field will be required in forms. This includes the admin and your own custom forms.
unique_together may be deprecated in the future. This is a list of lists that must be unique when considered together. It's used in the Django admin and is enforced at the database level (i.e., the appropriate UNIQUE statements are included in the CREATE TABLE statement).
The Django convention is to use the empty string, not NULL. The default values of null and blank are False. Also there is a special case, when you need to accept NULL values for a BooleanField , use NullBooleanField instead.
Firstly, blank (empty string) IS NOT same as null ('' != None).
Secondly, Django CharField when used through forms will be storing empty string when you leave field empty.
So if your field was something else than CharField you should just add null=True to it. But in this case you need to do more than that. You need to create subclass of forms.CharField and override it's clean method to return None on empty string, something like this:
class NullCharField(forms.CharField): def clean(self, value): value = super(NullCharField, self).clean(value) if value in forms.fields.EMPTY_VALUES: return None return value and then use it in form for your ModelForm:
class MyModelForm(forms.ModelForm): name = NullCharField(required=False, ...) this way if you leave it blank it will store null in database instead of empty string ('')
Using unique_together, you're telling Django that you don't want any two MyModel instances with the same parent and name attributes -- which applies even when name is an empty string.
This is enforced at the database level using the unique attribute on the appropriate database columns. So to make any exceptions to this behavior, you'll have to avoid using unique_together in your model.
Instead, you can get what you want by overriding the save method on the model and enforcing the unique restraint there. When you try to save an instance of your model, your code can check to see if there are any existing instances that have the same parent and name combination, and refuse to save the instance if there are. But you can also allow the instance to be saved if the name is an empty string. A basic version of this might look like this:
class MyModel(models.Model): ... def save(self, *args, **kwargs): if self.name != '': conflicting_instance = MyModel.objects.filter(parent=self.parent, \ name=self.name) if self.id: # This instance has already been saved. So we need to filter out # this instance from our results. conflicting_instance = conflicting_instance.exclude(pk=self.id) if conflicting_instance.exists(): raise Exception('MyModel with this name and parent already exists.') super(MyModel, self).save(*args, **kwargs) Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With