Opened 15 months ago
Last modified 5 months ago
#35813 assigned Bug
Makemigrations not properly tracking changes to unmanaged models — at Initial Version
| Reported by: | Hanny G | Owned by: | |
|---|---|---|---|
| Component: | Migrations | Version: | 5.1 |
| Severity: | Normal | Keywords: | makemigrations, unmanaged |
| Cc: | Hanny G, Simon Charette, Imran Ahmed Khan | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I believe there is a bug with the makemigrations command.
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 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.
I have an if this is unclear.
For this example let's assume we have two models: UnmanagedThing and ManagedThing (unmanaged and managed, respectively)
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)
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 believe this to be a valid bug worth fixing if the docs