I was attempting to create a custom model field and use it in a model as the docs demonstrate for BetterCharField shown here (you might have to scroll a bit down): https://docs.djangoproject.com/en/3.0/howto/custom-model-fields/#custom-database-types
My code in my models.py is as follows, almost verbatim from the docs example:
from django.db import models
# Create your models here.
class BetterCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super().__init__(*args, **kwargs)
def db_type(self, connection):
return "char({})".format(self.max_length)
class MyModel(models.Model):
my_field = BetterCharField(25)
However, when trying to run python manage.py makemigrations with this models.py file, I get the following error every time:
Traceback (most recent call last):
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/db/migrations/state.py", line 413, in from_model
fields.append((name, field.clone()))
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 512, in clone
return self.__class__(*args, **kwargs)
TypeError: __init__() missing 1 required positional argument: 'max_length'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "manage.py", line 21, in <module>
main()
File "manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/core/management/base.py", line 328, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/core/management/base.py", line 369, in execute
output = self.handle(*args, **options)
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/core/management/base.py", line 83, in wrapped
res = handle_func(*args, **kwargs)
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/core/management/commands/makemigrations.py", line 142, in handle
ProjectState.from_apps(apps),
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/db/migrations/state.py", line 221, in from_apps
model_state = ModelState.from_model(model)
File "/Users/dark_knight/test/venv/lib/python3.7/site-packages/django/db/migrations/state.py", line 418, in from_model
e,
TypeError: Couldn't reconstruct field my_field on polls.MyModel: __init__() missing 1 required positional argument: 'max_length'
Why is this failing? I had yet to create any migrations at all for this project, let alone the field and model given here. I have my positional argument as 25 given to BetterCharField when I initialize it in my models.py file. What am I missing? I had a much more complex use case, but I built this example in a brand new test django project/app straight from the documentation, and it still fails.
This is documented behaviour:
You can’t modify the number of positional arguments in an already migrated custom field without raising a
TypeError. The old migration will call the modified__init__method with the old signature. So if you need a new argument, please create a keyword argument and add something likeassert 'argument_name' in kwargsin the constructor.