32👍
The deconstruct()
method is used to help perform model migrations that aren’t able to automatically be handled by the system. Let’s walk through a scenario where deconstruct would get called.
Let’s say we had some model, and we added a custom field to it. The we try to migrate with python manage.py makemigrations
.
We encounter the following error:
ValueError: Cannot serialize: Foo
There are some values Django cannot serialize into migration files.
It turns out that there’s already a related ticket that’s been filed with the Django Project, let’s check it out.
One of the core developers responded that this is intended behavior, because our field contains a callable.
So, we missed something in the documentation. There’s a callable value being stored, and it can’t be automatically migrated for some reason. What can we do?
Well, in addition to telling us about the ValueError
, manage.py
also gave us a useful link to the documentation:
Once on that page, scroll down a bit, until we get to the section about serializing values.
Django can serialize the following:
- …
- Anything with a custom deconstruct() method (see below)
- …
Well, let’s see below:
You can let Django serialize your own custom class instances by giving
the class a deconstruct() method. It takes no arguments, and should
return a tuple of three things (path, args, kwargs):
- path should be the Python path to the class, with the class name
included as the last part (for example, myapp.custom_things.MyClass).
If your class is not available at the top level of a module it is not
serializable.- args should be a list of positional arguments to pass to
your class’ init method. Everything in this list should itself be
serializable.- kwargs should be a dict of keyword arguments to pass to
your class’ init method. Every value should itself be
serializable.
Note that the deconstruct() method works hand in hand with __eq__()
, as stated by the documentation:
To prevent a new migration from being created each time makemigrations is run, you should also add a __eq__() method to the decorated class. This function will be called by Django’s migration framework to detect changes between states.
In my case, the mistake was adding parenthesis after a value that should not have been called, but in many cases you’ll want to implement that deconstruct method for migrations. (Here’s another useful link that has an example.)