# Bug or Proposal: makemigrations and unmanaged models

**URL:** <https://forum.djangoproject.com/t/bug-or-proposal-makemigrations-and-unmanaged-models/35373>\
**Category:** ORM\
**Created:** [October 3, 2024, 5:36pm UTC](https://forum.djangoproject.com/t/bug-or-proposal-makemigrations-and-unmanaged-models/35373 "2024-10-03T17:36:12Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![hannylicious](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/hannylicious/32/29866_2.png) [@hannylicious](https://forum.djangoproject.com/u/hannylicious)\
**Post date:** [October 3, 2024, 5:36pm UTC](https://forum.djangoproject.com/t/bug-or-proposal-makemigrations-and-unmanaged-models/35373/1 "2024-10-03T17:36:12Z")

</div>

This is either a bug with the `makemigrations` command, or I believe we may want to reconsider how we deal with unmanaged models and the tracking of their changes with migrations. For what it’s worth, I’m talking specifically here with the `makemigrations` command and migrations files themselves - as I am aware they are distinctly different from the process that happens when someone runs `migrate` and the database is altered.

**The Issue/Bug:** Changes to unmanaged models are not being recognized by `makemigrations`. If those same changes are applied to a managed model, `makemigrations` recognizes the changes.

The `makemigrations` command tracks the Creation of an unmanaged model, the Deletion of an unmanaged model, but does not track changes to the attributes/fields of an unmanaged model (see example below for more depth).

**Concerns/Discussion:** If we are including unmanaged models in migration files ‘for somewhat of a historical reference of changes to a model’ (my rough interpretation) then all changes should be recorded similarly for both managed & unmanaged models. Otherwise, what is the point in recording anything for the unmanaged models?

Because if you create an unmanaged model, make the initial migration and then have to change a field on it, `makemigrations` will not detect the change you made. At that point, your migrations (the ‘historical reference’) are out of sync with the current reality of the model.

That’s what makes me think it may be a bug. If we’re tracking managed model alterations via migrations and we’re tracking creation and deletion of unmanaged models via migrations, we should either:

- a. track alterations to unmanaged models via migrations (for historical purpose)
- b. not include unmanaged models in migrations at all (honestly, I would prefer this option)

I have some examples if I am being unclear.  
For this example let’s assume we have two models: `UnmanagedThing` and `ManagedThing` (unmanaged and managed, respectively)

```auto
class UnmanagedThing(models.Model):
    """
    This model represents an unmanaged Thing.
    """

    id = models.IntegerField(
        db_column="thingID", primary_key=True
    )
    thing_number = models.CharField(max_length=16, db_column="thingNumber")
    thing_name = models.CharField(max_length=50, db_column="thingName")
    grade_level = models.CharField(max_length=2, db_column="gradeLevel")

    class Meta:
        """Meta options for the UnmanagedThing model."""

        verbose_name = "Unmanaged Thing"
        verbose_name_plural = "Unmanaged Things"
        managed = False
        db_table = "some_table_name"

    def __str__ (self) -> str:
        """Return the course name."""
        return f"{self.thing_name}"

class ManagedThing(models.Model):
    """
    This model represents an unmanaged Thing.
    """

    id = models.IntegerField(
        db_column="thingID", primary_key=True
    )
    thing_number = models.CharField(max_length=16, db_column="thingNumber")
    thing_name = models.CharField(max_length=50, db_column="thingName")
    grade_level = models.CharField(max_length=2, db_column="gradeLevel")

    class Meta:
        """Meta options for the UnmanagedThing model."""

        verbose_name = "Unmanaged Thing"
        verbose_name_plural = "Unmanaged Things"

    def __str__ (self) -> str:
        """Return the course name."""
        return f"{self.thing_name}"

```

If I run `makemigrations` I get the expected `0001...` migration file and I see both models created with their respective fields/options.

If I change `thing_name` to be an `IntegerField` on the managed model and run `makemigrations`, I see a `0002...` migration file created with the expected ‘AlterField’ inside of it.

If I change `thing_name` to be an `IntegerField` on the unmanaged model and run `makemigrations`, I see “No changes detected” and nothing is created. However, now there is a disconnect between my model and what is recorded in migrations.

Everything else works similarly between the two; if I delete either one, it’s recorded in a migration file. If I change the unmanaged model to ‘managed’, it creates a migration file for that (and subsequently begins tracking changes as expected with `makemigrations`

So I guess ultimately: is this a bug? It sure feels like we should be tracking changes the same between them. Per the django docs: " You should think of migrations as a version control system for your database schema. `makemigrations` is responsible for packaging up your model changes into individual migration files - analogous to commits"; it’s not behaving that way currently, so I can’t see it’s current behavior in line with that definition.

---

<div class="post-metadata">

**Author:** ![charettes](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/charettes/32/27_2.png) [@charettes](https://forum.djangoproject.com/u/charettes)\
**Post date:** [October 3, 2024, 10:07pm UTC](https://forum.djangoproject.com/t/bug-or-proposal-makemigrations-and-unmanaged-models/35373/2 "2024-10-03T22:07:36Z")

</div>

Thanks for putting this together.

I do believe that this is qualifies as a bug as I would expect managed model changes to be tracked but noop at application time.

This lack of proper tracking might explain surface bugs like [this one](https://code.djangoproject.com/ticket/27319).
