SubfieldBase has been deprecated Django warning for DurationField
by Sebastien Mirolo on Sun, 24 Jul 2016
As we are getting ready for a Django 1.10 upgrade,
it is time to take care of one of the most baffling warning in the code base
RemovedInDjango110Warning: SubfieldBase has been deprecated
.
This lead to a long journey through code, documentation, and release notes.
Soon after we upgraded to Django 1.9, we stumbled upon this warning in the djaodjin-survey code base.
six.py:778: RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.
At first I thought maybe we are using an old version of the six
library but that was not the case. The warning gets triggered from somewhere
in our code base, though there is no clue which statements leads to it.
I can remember the days when tracking errors involved a debugger breakpoint
and patching assembly code on the fly - "Matrix" style. Today since
most of Python code and libraries are open source, we can just add a print
statement in the six.py
file as such:
def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" # This requires a bit of explanation: the basic idea is to make a dummy # metaclass for one level of class instantiation that replaces itself with # the actual metaclass. class metaclass(meta): def __new__(cls, name, this_bases, d): + print "XXX cls=%s, name=%s" % (cls, name) return meta(name, bases, d) return type.__new__(metaclass, 'temporary_class', (), {})
The following run of manage.py
shows that the warning message
is triggered by
durationfield.db.models.fields.duration.DurationField
.
Maybe we need to update the django-durationfield
library then?
Nope. We have the latest version of django-durationfield
installed so let's start browsing through the source on GitHub. Maybe a patch
was committed on django-durationfield master
and not released yet.
The description of django-durationfield reads "Temporary reusable Django application for adding a DurationField, until Django issue #2443 is resolved."
We read through the ticket which leads us to Django 1.8 release notes. Obviously, the best course of action from then on is to modify our code base to replace uses of django-durationfield by the Django models field.
-from durationfield.db.models.fields.duration import DurationField +from django.db.models.fields import DurationField
The caveat being that django-durationfield takes an integer representing the number of microseconds while Django takes a datetime.timedelta object. Furthermore, Django takes advantages of the interval datatype on Postgresql. That means we will need to migrate the schema and data in the database.
After much tinkering around to convert bigint microseconds into a postgres interval, the following code seems to do the trick.
ALTER TABLE survey_response ALTER COLUMN time_spent TYPE interval \ USING concat((time_spent/1000000.0)::text, ' second')::interval;
All looks well yet unit tests randomly fail. It seems like reading
microseconds back from the SQLite database sometimes returns None
.
After spending some time reviewing the changes, it does not seem a logic
bug in our code base. It is time for another Google search and sure enough
a SQLite database sometimes returns None. issue was already reported and fixed in Django 1.9.5.
What a long day for a minor change that removes a warning. If you are curious at to the reason for the warning in the first place, read SubfieldBase has been deprecated in the Django 1.8 release notes.
More to read
If you are looking for more posts about Django, Multi-tier Implementation in Django, Django, Gunicorn and Syslog-ng or Nginx, Gunicorn and Django are worth reading next.
More technical posts are also available on the DjaoDjin blog, as well as business lessons we learned running a SaaS application hosting platform.