#34710 closed Uncategorized (invalid)

Infinite migrations using models.Choices

Reported by: Div Shekhar Owned by: nobody
Component: Migrations Version: 4.2
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Summary:

  • Infinite migrations generated when using enum which is subclass of models.Choices
  • Issue does NOT occur with models.TextChoices
  • Workaround: use default=EnumClass.SOME_VALUE.value

Steps to reproduce:

  • In a new app, define the following model:
class CoinTossResult(models.Model):
    class CoinFace(models.Choices):
        HEADS = "h"
        TAILS = "t"

    result = models.CharField(
        max_length=1,
        choices=CoinFace.choices,
        default=CoinFace.HEADS,
    )
  • Run makemigrations multiple times. After the initial migration, an extra migration is generated repeatedly:
(myapp) ~/work/myapp % ./manage.py makemigrations
Migrations for 'foo':
  foo/migrations/0001_initial.py
    - Create model CoinTossResult

(myapp) ~/work/myapp % ./manage.py makemigrations
Migrations for 'foo':
  foo/migrations/0002_alter_cointossresult_result.py
    - Alter field result on cointossresult

(myapp) ~/work/myapp % ./manage.py makemigrations
Migrations for 'foo':
  foo/migrations/0003_alter_cointossresult_result.py
    - Alter field result on cointossresult

(myapp) ~/work/myapp % ./manage.py makemigrations
Migrations for 'foo':
  foo/migrations/0004_alter_cointossresult_result.py
    - Alter field result on cointossresult

(myapp) ~/work/myapp % cat foo/migrations/0002_alter_cointossresult_result.py
# Generated by Django 4.2.2 on 2023-07-13 11:00

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('foo', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='cointossresult',
            name='result',
            field=models.CharField(choices=[('h', 'Heads'), ('t', 'Tails')], default='h', max_length=1),
        ),
    ]

(myapp) ~/work/myapp % diff foo/migrations/0002_alter_cointossresult_result.py foo/migrations/0003_alter_cointossresult_result.py
9c9
<         ('foo', '0001_initial'),
---
>         ('foo', '0002_alter_cointossresult_result'),

(myapp) ~/work/myapp % diff foo/migrations/0003_alter_cointossresult_result.py foo/migrations/0004_alter_cointossresult_result.py
9c9
<         ('foo', '0002_alter_cointossresult_result'),
---
>         ('foo', '0003_alter_cointossresult_result'),

Same steps while using the workaround:

(myapp) ~/work/myapp % git diff
diff --git a/foo/models.py b/foo/models.py
index 50e0ad0..e553ad7 100644
--- a/foo/models.py
+++ b/foo/models.py
@@ -8,5 +8,5 @@ class CoinTossResult(models.Model):
     result = models.CharField(
         max_length=1,
         choices=CoinFace.choices,
-        default=CoinFace.HEADS,
+        default=CoinFace.HEADS.value,
     )

(myapp) ~/work/myapp % ./manage.py makemigrations foo
Migrations for 'foo':
  foo/migrations/0001_initial.py
    - Create model CoinTossResult

(myapp) ~/work/myapp % ./manage.py makemigrations foo
No changes detected in app 'foo'

Change History (3)

comment:1 by David Sanders, 10 months ago

Hi Div Shekhar,

In order to get your example working you'd need to specify the type like so:

class CoinTossResult(models.Model):
    class CoinFace(str, models.Choices):
        ...

I don't think this is an issue with Django – though there may be some documentation updates that could make this clearer when defining custom Choices classes. I'll leave it up to felixx or nessita to decide whether this ticket is invalid 😊

comment:2 by Div Shekhar, 10 months ago

My bad - you can close this out.

I was thrown coming from django-model-utils's Choices and incorrectly assumed TextChoices had extra features I didn't need, whereas Choices here is closer to an abstract base class.

Last edited 10 months ago by Div Shekhar (previous) (diff)

comment:3 by Natalia Bidart, 10 months ago

Resolution: invalid
Status: newclosed

Closing following latest comment from reporter.

Note: See TracTickets for help on using tickets.
Back to Top