I am using ProjectState to migrate to a new attributes of a table. I am trying to understand the ModelState and ProjectState using of migrations API in Django 3.0.3.
To start, you need to be using the model metaclass, ie. ModelBase, and not type
:
from django.db.models.base import ModelBase
model_definition = ModelBase(
model_item.table_name,
bases,
model_config
)
Once you use the proper metaclass, you will likely receive a myriad of errors, since you are using many class attributes that ModelBase
sets internally, and is not expecting you to set yourself.
Instead of dumping all the attributes that your model has, you should only set the attributes that ModelBase
expects to be set on a traditional model, which includes:
__module__
and __qualname__
Meta
Everything else should be omitted.
So for example, if you have a models that look like this, in the module myapp.models
:
class Parent(models.Model):
name = models.CharField(max_length=45)
class Child(models.Model):
name = models.CharField(max_length=45)
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
class ModelWithMeta(models.Model):
class Meta:
db_table = 'some_table'
The dynamic version of these models need to look like this:
from django.db import models
from django.db.models.base import ModelBase
bases = (models.Model,)
Parent = ModelBase('Parent', bases, {
'__module__': 'myapp.models',
'__qualname__': 'Parent',
'name': models.CharField(max_length=45),
})
Child = ModelBase('Child', bases, {
'__module__': 'myapp.models',
'__qualname__': 'Child',
'name': models.CharField(max_length=45),
'parent': models.ForeignKey('myapp.Parent', on_delete=models.CASCADE),
})
ModelWithMeta = ModelBase('ModelWithMeta', bases, {
'__module__': 'myapp.models',
'__qualname__': 'ModelWithMeta',
'Meta': type('Meta', (), {'db_table': 'some_table'}),
})
I don't understand the purpose of your migration code, so I will assume that it was a hack in attempt to get the dynamic models working, which means you can probably throw it out altogether and use the builtin migration loader, ie:
python3 manage.py makemigrations myapp && python3 manage.py migrate myapp
I you aren't familiar with python metaclasses, I'd recommend reading up on them, since it's a prerequisite to understand my code.