Django unique, null and blank CharField giving 'already exists' error on Admin page

前端 未结 7 2082
旧巷少年郎
旧巷少年郎 2021-01-01 13:30

I\'ve been getting the most weird error ever. I have a Person model

class Person(models.Model):
    user = models.OneToOneField(User, primary_key=True)
    f         


        
7条回答
  •  梦毁少年i
    2021-01-01 14:00

    It's important to solve this at the model level, not at the form level, since data can enter through APIs, through import scripts, from the shell, etc. The downside of setting null=True on a CharField is that the column could end up with both empty strings and NULLs, which is slightly ambiguous but not generally a problem in my experience. If you're willing to live with that ambiguity, here's how to do it in a few steps:

    1) Set null=True, blank=True on the field and migrate in the change.

    2) Massage your data so that all existing empty strings are changed to NULLs:

    items = Foo.objects.all()
    for item in items:
      if not item.somefield:
        item.somefield = None
        item.save()
    

    3) Add a custom save() method to your model:

    def save(self, *args, **kwargs):
        # Empty strings are not unique, but we can save multiple NULLs
        if not self.somefield:
            self.somefield = None
    
        super().save(*args, **kwargs)  # Python3-style super()
    

    4) Set unique=True on the field and migrate that in as well.

    Now you'll be able to store somefield as empty or as a unique value whether you're using the admin or any other data entry method.

    If you prefer not to have several migrations, here's an example of how to do it in a single migration:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    from django.db import migrations, models
    
    def set_nulls(apps, schema_editor):
        Event = apps.get_model("events", "Event")
        events = Event.objects.all()
        for e in events:
            if not e.wdid:
                e.wdid = None
                e.save()
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('events', '0008_something'),
        ]
    
        operations = [
            migrations.AlterField(
                model_name='event',
                name='wdid',
                field=models.CharField(blank=True, max_length=32, null=True),
            ),
            migrations.RunPython(set_nulls),
            migrations.AlterField(
                model_name='event',
                name='wdid',
                field=models.CharField(blank=True, max_length=32, null=True, unique=True),
            ),
        ]
    

提交回复
热议问题