Welcome to the DjaoDjin Blog!

A place to share experiences in building Software-as-a-Service.

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 subscription hosting platform.