djangodjango-modelsdjango-model-field

Are there advantages to using IntegerChoices field in a Django model if it's not shown to users?


I'm using IntegerChoices in my Django (3.2) model.

class AType(db.IntegerChoices):
    UNKNOWN = 0, 'Unknown'
    SOMETHING = 1, 'Something'
    ANOTHER_THING = 2, 'Another thing'
    A_THIRD_THING = 3, 'A third thing'


class MyObject(models.Model):
    a_type = db.IntegerField(choices=AType.choices)

(I've changed the choices to be more generic.)

Every time I add a value to AType, it produces a DB migration, which I faithfully apply.

a_type is strictly behind the scenes. Users never see it, so it's only in the admin UI, but I don't need it to be editable. So forms aren't really used.

Is there any impact on the DB (e.g., constraints) of these migrations?

Is there any other utility to having an IntegerChoices field, given that it's not displayed to a (non-staff) user, and not in a form?

If there's no utility, I'm thinking of just changing MyObject.a_type to an IntegerField, and continuing to use AType everywhere, but not having all the migrations.


Solution

  • Is there any impact on the DB (e.g., constraints) of these migrations?

    No impact to the schema. You can see this in python manage.py sqlmigrate myapp 000x_mymigration.

    However, it still does CREATE TABLE, INSERT INTO ... SELECT (expensive), DROP TABLE, ALTER TABLE.

    This is "by design" and "wontfix":

    Is there any other utility to having an IntegerChoices field, given that it's not displayed to a (non-staff) user, and not in a form?

    Yes, model validation.
    Reference: https://docs.djangoproject.com/en/3.2/ref/models/fields/#choices

    I'm thinking of just changing MyObject.a_type to an IntegerField, and continuing to use AType everywhere, but not having all the migrations.

    You can ignore choices by patching MigrationAutodetector in makemigrations and migrate.

    You can additionally ignore _verbose_name and help_text.

    mysite/apps.py:

    from django.apps import AppConfig
    from django.core.management.commands import makemigrations, migrate
    from django.db import models
    from django.db.migrations import autodetector
    
    
    class MigrationAutodetector(autodetector.MigrationAutodetector):
        ignored_field_attribute_names = [
            'choices',
            # '_verbose_name',
            # 'help_text',
        ]
    
        def deep_deconstruct(self, obj):
            if isinstance(obj, models.Field):
                for attr_name in self.ignored_field_attribute_names:
                    setattr(obj, attr_name, None)
            return super().deep_deconstruct(obj)
    
    
    class MySiteAppConfig(AppConfig):
        name = 'mysite'
    
        def ready(self):
            makemigrations.MigrationAutodetector = MigrationAutodetector
            migrate.MigrationAutodetector = MigrationAutodetector
            pass
    

    mysite/settings.py:

    INSTALLED_APPS = [
        # ...
        'mysite.apps.MySiteAppConfig',
    ]