There are several questions on StackOverflow regarding a field that is defined in a model, but does not appear in the database after making migrations and migrating.
What are the symptoms?
If we inspect the migration file that was constructed
by the makemigrations
command [Django-doc], we see that only a
subset of the fields (or none at all) are mentioned, and
some fields that have been defined in the model are thus
missing.
What is a possible fix?
Usually this is caused because we did not define that field correctly in the model. There are typically three variants to that problem.
Variant 1: Trailing comma
Some people tend to end the line of a field with a comma, for example:
from django.db import models
class MyModel(models.Model):
# a trailing comma ↓
name = models.CharField(max_length=128),
This will wrap the CharField
in a
singleton tuple (a tuple with one element). Django will
look for items in the class that are subclasses of the
Field
class [Django-doc]. While the tuple wraps
a CharField
that is a subclass of
Field
, a singleton tuple that contains such
element is not, so Django will not recognize
it.
In that case you thus drop the trailing comma, and work with:
from django.db import models
class MyModel(models.Model):
# no trailing comma ↓
name = models.CharField(max_length=128)
Variant 2: Using a colon between the name of the field and the field
Often people write classes like one writes a
dictionary literal: with a colon (:
)
between the key and the value. This thus can look
like:
from django.db import models
class MyModel(models.Model):
# ↓ a colon
name : models.CharField(max_length=128)
This is not a way to define a class
attribute. The colon is used for annotations. Indeed, if
we inspect MyModel
, we see:
>>> MyModel.name
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: type object 'MyModel' has no attribute 'name'
Colons are here used to create type
annotations. Indeed, if we inspect the
__annotations__
attribute of
MyModel
, we see:
>>> MyModel.__annotations__
{'name': <django.db.models.fields.CharField>}
We here thus made an annotation to specify that
name
will have a certain type, but we never
define name
at the class level.
We thus should replace the colon with an equals sign
(=
):
from django.db import models
class MyModel(models.Model):
# ↓ equals sign instead of a colon
name = models.CharField(max_length=128)
Variant 3: mixing form fields and model fields
Another common variant is mixing model
fields with form fields. It is easy to make
such mistake, since a lot of form fields have the same
class name as their model field. Especially if one uses
an IDE, and then for example writes
CharField
, it is possible that the IDE will
propose to import the wrong module. This thus could look
like:
from django.db import models
from django.forms import CharField
class MyModel(models.Model):
# ↓ CharField from the django.forms module
name = CharField(max_length=128)
Since this CharField
does not inherit
from the Field
of the
django.db.models
module, again Django will
not see this as a field that should be included in the
migration.
In Django model fields focus in storing data in the database, whereas form fields help to process data when a form is submitted. It thus makes no sense that model fields appear in forms, or that form fields appear in models.
Therefore it might be better to import the
django.db.models
module, and always use
models.CharField
in that case it gives a
visual hint that it is using the correct field:
from django.db import models
class MyModel(models.Model):
# ↓ import from the models module.
name = models.CharField(max_length=128)