[Django]-Django data migration – class variable unavailable via get_model()

0👍

Models are registered in apps. There’s django.apps.apps that’s using the "latest" model state, and the apps that are provided in your RunPython.

https://github.com/django/django/blob/c3d7a71f836f7cfe8fa90dd9ae95b37b660d5aae/django/db/migrations/operations/special.py#L193

The apps in RunPython are generated using the from_state. In other words, when Django needs to run 10 migrations and you need RunPython in 7th, it provides the "state" of the database from the 7th migration. It doesn’t matter if you run them one by one every month or all at once – the state of the 7th migration will be the same for all models across your entire project.

That’s all that’s passed in the migration – the state of the model (and all the other models). It can’t deserialize into the model with your business logic, as it changes over time. Any constants or methods are not available during the migration. It’s best to copy as much as possible into the migration itself. It doesn’t matter if it’s ugly, as long as you can rerun the migration over time and expect the same outcome.

It looks like the Driver class, when it’s included via apps.get_model(), is different to a straight import

If you inspect, you should see it says something like __fake__.Driver. Again, it’s the representation of your table, not the model itself.

Driver.PENDING

I never liked putting constants/choices in your models. If I was to handle such migration, I’d first create a choices module

# choices.py

class DriverStatus(models.TextChoices):
    PENDING = "pending"

Then in your migration

try:
    from app_name.choices import DriverStatus
    PENDING = DriverStatus.PENDING
except ImportError:
    PENDING = "pending"

Now you can migrate pending drivers and the state of your migration is local.

Leave a comment