When I migrate or run the testserver, I get this following complaint.
System check identified some issues:
WARNINGS:
contentmanager.ContentElement.text: (fields.E010) JSONField default should be a callable instead of an instance so that it’s not shared between all field instances.
HINT: Use a callable instead, e.g., use dict
instead of {}
.
Here’s the referenced field:
text = JSONField(default=dict(settings.MULTITEXT_CHOICES))
And here’s settings.MULTITEXT_CHOICES:
# (*Language*, _('*Display Name*')),
(MULTITEXT_LANGUAGES['ENGLISH'], 'English'),
(MULTITEXT_LANGUAGES['GERMAN'], 'German'),
]
So from my understanding, dict() is a callable. However I’m using it on a list of lists. So, does that mean, that I’m creating an independent instance of dict which points to the same values, as the list of lists? Is that why I get the complaint?
The values in the settings.py don’t ever change during runtime which makes me think, that I can ignore the warning.
When you call dict()
in the model definition, you get a single instance returned, that is then shared between all instances, which isn’t likely what you want.
Since it’s not a plain dictionary you need, you can’t just pass dict
(Note no ()
so the callable, not the returned dictionary when you call it, with the ()
)
Instead, you can create a function that just makes and returns the dict(...)
call you’ve got currently, this creating a new dictionary each time, so instanced won’t share the default.
Hope that helps.
1 Like
Thanks, that helps. Maybe you can answer another question on that regard: the method I would write couldn’t live inside the class of the model, because then it doesn’t exist when it is needed. I had this case before and so I just placed the method in front of the class, but then it is a classless static method. Is that the right place for the method to be or should it be somewhere else?
I think it might be one of those few cases where a lambda would be appropriate…
default=lambda:dict(settings.MULTITEXT_CHOICES)
(On the phone so I can’t test that. You might need ()
)
Otherwise you’d just put it in a named function.
To add to @carltongibson’s sage advice, and only to address your specific question, I will say that yes, in this case, under these circumstances, it’s perfectly acceptable for that method to exist outside a class. (I am not one of those that believes in “Classes everywhere”. I also tend to work under the general principle that any solution that works is a good solution.)
Ken
Hey Carlton,
unfortunately a lambda is not the solution. I got an error when trying to migrate.
Migrations are just Python files containing the old definitions of your models - thus, to write them, Django must take the current state of your models and serialize them out into a file. While Django can serialize most things, there are some things that we just can’t serialize out into a valid Python representation…
Django can serialize the following: Any function or method reference… in module’s top-level scope
Django cannot serialize: Lambdas
Source
So a function it will be.
Ah, super. There you are then. Use a function it is.