Unique fields that allow nulls in Django

前端 未结 10 1014
闹比i
闹比i 2020-11-28 01:56

I have model Foo which has field bar. The bar field should be unique, but allow nulls in it, meaning I want to allow more than one record if bar field is null,

相关标签:
10条回答
  • 2020-11-28 02:31

    I recently had the same requirement. Instead of subclassing different fields, I chose to override the save() metod on my model (named 'MyModel' below) as follows:

    def save(self):
            """overriding save method so that we can save Null to database, instead of empty string (project requirement)"""
            # get a list of all model fields (i.e. self._meta.fields)...
            emptystringfields = [ field for field in self._meta.fields \
                    # ...that are of type CharField or Textfield...
                    if ((type(field) == django.db.models.fields.CharField) or (type(field) == django.db.models.fields.TextField)) \
                    # ...and that contain the empty string
                    and (getattr(self, field.name) == "") ]
            # set each of these fields to None (which tells Django to save Null)
            for field in emptystringfields:
                setattr(self, field.name, None)
            # call the super.save() method
            super(MyModel, self).save()    
    
    0 讨论(0)
  • 2020-11-28 02:32

    If you have a model MyModel and want my_field to be Null or unique, you can override model's save method:

    class MyModel(models.Model):
        my_field = models.TextField(unique=True, default=None, null=True, blank=True) 
    
        def save(self, **kwargs):
            self.my_field = self.my_field or None
            super().save(**kwargs)
    

    This way, the field cannot be blank will only be non-blank or null. nulls do not contradict uniqueness

    0 讨论(0)
  • 2020-11-28 02:35

    Another possible solution

    class Foo(models.Model):
        value = models.CharField(max_length=255, unique=True)
    
    class Bar(models.Model):
        foo = models.OneToOneField(Foo, null=True)
    
    0 讨论(0)
  • 2020-11-28 02:41

    The quick fix is to do :

    def save(self, *args, **kwargs):
    
        if not self.bar:
            self.bar = None
    
        super(Foo, self).save(*args, **kwargs)
    
    0 讨论(0)
  • 2020-11-28 02:41

    This is fixed now that https://code.djangoproject.com/ticket/4136 is resolved. In Django 1.11+ you can use models.CharField(unique=True, null=True, blank=True) without having to manually convert blank values to None.

    0 讨论(0)
  • 2020-11-28 02:42

    Because I am new to stackoverflow I am not yet allowed to reply to answers, but I would like to point out that from a philosophical point of view, I can't agree with the most popular answer tot this question. (by Karen Tracey)

    The OP requires his bar field to be unique if it has a value, and null otherwise. Then it must be that the model itself makes sure this is the case. It cannot be left to external code to check this, because that would mean it can be bypassed. (Or you can forget to check it if you write a new view in the future)

    Therefore, to keep your code truly OOP, you must use an internal method of your Foo model. Modifying the save() method or the field are good options, but using a form to do this most certainly isn't.

    Personally I prefer using the CharNullField suggested, for portability to models I might define in the future.

    0 讨论(0)
提交回复
热议问题