[Django]-Does Django create useless migrations?

5đź‘Ť

âś…

Django makes abstraction of the backend used. Indeed, you can use a different backend, by altering the settings.py file. In fact you can define a backend yourself.

All changes to the models thus can have impact on the database. You could for example define a backend that uses the verbose_name of a column as the “comment string” you frequently can add to such column at the database side. If you for example define choices, then a backend could, for some databases, try to enforce these choices at database level.

Since, as said before, Django aims to work unaware of the backend used, it thus aims to be conservative, and make migrations for a lot of model changes. For some of these, the backend will decide to simply do nothing. So no query is constructed, and nothing is changed at the database side. You can indeed see such changes as “useless migrations”. But keep in mind that if you later would use a different backend, these “useless migrations” might in fact do something.

Since such migrations do not do anything on the database side, these are however usually not time cosuming. You might want to look to “squash” migration files [Django-doc] together, and thus reduce the number of migration files used. The migrations will still be part of the file, but since there are no queries involved, it will usually not do much harm.

Furthermore, you can in fact patch the deconstruct function on a field, such that the help_text, etc. do not appear in the result of a deconstruct call anymore and thus are not visible to the “detector”. This Gist script shows a way to patch the makemigration command:

"""
Patch the creation of database migrations in Django
Import this early from `__init__.py``.
- Don't want verbose_name changes in the migrations file.
- Don't want help_text in the migrations file.
"""
from functools import wraps

from django.db.models import Field


def patch_deconstruct(old_func, condition):
    """
    Patch the ``Field.deconstruct`` to remove useless information.
    This only happens on internal apps, not third party apps.
    """

    @wraps(old_func)
    def new_deconstruct(self):
        name, path, args, kwargs = old_func(self)
        # AutoField has no model on creation, but can be skipped
        if hasattr(self, 'model') and condition(self):
            kwargs.pop('verbose_name', None)
            kwargs.pop('help_text', None)
        return name, path, args, kwargs
    return new_deconstruct


Field.deconstruct = patch_deconstruct(Field.deconstruct, lambda self: self.model.__module__.startswith('apps.'))

Leave a comment