20

On upgrade to Django 1.9, I now get the warning

RemovedInDjango110Warning: SubfieldBase has been deprecated. Use Field.from_db_value instead.

I see where the problem arises. I have some custom field definitions, and in them I have __metaclass__ = models.SubfieldBase. For example,

class DurationField(models.FloatField):

    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):

    ...

If the __metaclass__ statement is deprecated, what am I supposed to replace it with exactly?

Do I just take it out and add a from_db_value method like in the example here: https://docs.djangoproject.com/en/1.9/howto/custom-model-fields/#converting-values-to-python-objects ?

And how are from_db_value and to_python different? The both seem to convert database data to Python objects?

mjandrews
  • 2,392
  • 4
  • 22
  • 39

2 Answers2

41

Yes, you should just remove __metaclass__ line and add from_db_value() and to_python():

class DurationField(models.FloatField):

    def __init__(self, *args, **kwargs):
        ...

    def from_db_value(self, value, expression, connection, context):
        ...

    def to_python(self, value):
        ...

As described here: https://docs.djangoproject.com/en/1.9/ref/models/fields/#field-api-reference, to_python(value) converts the value (can be None, string or object) into the correct Python object.

from_db_value(value, expression, connection, context) converts a value as returned by the database to a Python object.

So, both methods return Python objects, but they are used by Django in different situations. to_python() is called by deserialization and during the clean() method used from forms. from_db_value() is called when the data is loaded from the database

ozren1983
  • 1,891
  • 1
  • 16
  • 34
  • 2
    this is very good and comprehensive answer. @mjandrews: why haven't you marked it as a final answer? – pt12lol Nov 16 '16 at 16:18
  • I've found that without the metaclass, the `to_python` isn't always called the same. For example, if you create a new instance of an object and then try to read the custom field it won't call the methods where with the metaclass it did call the method. – Tim Tisdall Feb 20 '18 at 19:17
5

While ozren is right, there is one huge difference, SubfieldBase had a really dirty side effect, it always called the to_python method on value assignment to the given model field. I have been recently bitten by this while upgrading from Django 1.9 to 1.10.

SEE:

https://docs.djangoproject.com/en/2.1/releases/1.8/#subfieldbase

jbub
  • 2,586
  • 23
  • 23
  • 2
    another link might help https://docs.djangoproject.com/en/2.1/ref/models/fields/#django.db.models.Field.from_db_value – Mauricio Cortazar May 23 '18 at 14:14
  • For anyone wondering how the whole solution looks, it is described under this question: https://stackoverflow.com/questions/39392343/how-do-i-make-a-custom-model-field-call-to-python-when-the-field-is-accessed-imm – Petr Dlouhý Sep 02 '22 at 21:09