How to set default value for a model field based on enum in Django?

Viewed 702

I'm using Django 2.2.5 and have multiple choice fields based on enums in my models. For an unknown reason I now get a migration error when using an enum for choice field during migration:

django.db.utils.OperationalError: (1067, "Invalid default value for 'protocol'")

model.py

from django.db import models
# See class above
from .utils import NetworkProtocolList

class Networks(models.Model):
    ipv4 = models.GenericIPAddressField(blank=False, null=False)
    protocol = models.CharField(choices=NetworkProtocolList.choices(), max_length=20,default=NetworkProtocolList.ETH)

    class Meta:
        managed = True
        db_table = 'networks'

utils.py

from enum import Enum

class NetworkProtocolList(Enum):
    ETH = 'Ethernet'
    MPLS = 'MPLS' 
   
    @classmethod
    def choices(cls):
        return [(key.name, key.value) for key in cls]  

I issued

manage.py makemigrations

and subsequent

manage.py migrate

generated the following error:

django.db.utils.OperationalError: (1067, "Invalid default value for 'protocol'")

xxxx_auto_xxxxxxxx_xxxx.py

# Auto generated migration file

import my_.utils
from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('my_app', 'yyyy_auto_yyyyyyyy_yyyy'),
    ]

    operations = [
        migrations.AddField(
            model_name='networks',
            name='protocol',
            # Field definition here, pay attention to the default value
            field=models.CharField(choices=[('ETH', 'Ethernet'), ('MPLS', 'MPLS')], default=my_app.utils.NetworkProtocolList('Ethernet'), max_length=20),
        ),
    ]

Than I edited migration file to manually set the default to a string instead of calling enum class:

xxxx_auto_xxxxxxxx_xxxx.py

# Edited migration file

import my_.utils
from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('my_app', 'yyyy_auto_yyyyyyyy_yyyy'),
    ]

    operations = [
        migrations.AddField(
            model_name='networks',
            name='protocol',
            # Field definition here, pay attention to the modified default value
            field=models.CharField(choices=[('ETH', 'Ethernet'), ('MPLS', 'MPLS')], default='Ethernet', max_length=20),
        ),
    ]

Now migration works properly but I wonder why I can't define default value like before using the enum instead of a litteral string, because I have other model field for whom this has worked properly.

Is that a bug, what am I lissing here, How to set default value for a model field based on enum in Django?

1 Answers

Since you are using Django<3.X, Django isn't able to identify the enum value. So, use the .value property of enum class as

protocol = models.CharField(
    choices=NetworkProtocolList.choices(),
    max_length=20,
    default=NetworkProtocolList.ETH.value # <--- change is here
)
Related