How do I make a custom model Field call to_python when the field is accessed immediately after initialization (not loaded from DB) in Django >=1.10?
<p>After upgrading from Django <code>1.9</code> to <code>1.10</code>, I've experienced a change in behaviour with a field provided by the django-geolocation package.</p>

<p>This is the change that was made for <code>1.10</code> compatibility that broke the behaviour: <a href="https://github.com/philippbosch/django-geoposition/commit/689ff1651a858d81b2d82ac02625aae8a125b9c9">https://github.com/philippbosch/django-geoposition/commit/689ff1651a858d81b2d82ac02625aae8a125b9c9</a></p>

<p>Previously, if you initialized a model with a <code>GeopositionField</code>, and then immediately accessed that field, you would get back a <code>Geoposition</code> object. Now you just get back the string value that you provided at initialization.</p>

<p>How do you achieve the same behaviour with Django <code>1.10</code>? Is there another method like <code>from_db_value</code> that needs to be overridden to call <code>to_python</code>?</p>

<p>After lots of digging it turns out that in <code>1.8</code> the behaviour of custom fields was changed in such a way that <code>to_python</code> is no longer called on assignment to a field.</p>

<p><a href="https://docs.djangoproject.com/en/1.10/releases/1.8/#subfieldbase">https://docs.djangoproject.com/en/1.10/releases/1.8/#subfieldbase</a></p>

<blockquote>
  <p>The new approach doesnât call the to_python() method on assignment as was the case with SubfieldBase. If you need that behavior, reimplement the Creator class from Djangoâs source code in your project.</p>
</blockquote>

<p>Here's a Django ticket with some more discussion on this change: <a href="https://code.djangoproject.com/ticket/26807">https://code.djangoproject.com/ticket/26807</a></p>

<p>So in order to retain the old behaviour you need to do something like this:</p>

<pre><code>class CastOnAssignDescriptor(object):
    """
    A property descriptor which ensures that `field.to_python()` is called on _every_ assignment to the field.
    This used to be provided by the `django.db.models.subclassing.Creator` class, which in turn
    was used by the deprecated-in-Django-1.10 `SubfieldBase` class, hence the reimplementation here.
    """

    def __init__(self, field):
        self.field = field

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        return obj.__dict__[self.field.name]

    def __set__(self, obj, value):
        obj.__dict__[self.field.name] = self.field.to_python(value)
</code></pre>

<p>And then add this to the custom field:</p>

<pre><code>def contribute_to_class(self, cls, name):
    super(MyField, self).contribute_to_class(cls, name)
    setattr(cls, name, CastOnAssignDescriptor(self))
</code></pre>

<p>Solution was taken from this pull request: <a href="https://github.com/hzdg/django-enumfields/pull/61">https://github.com/hzdg/django-enumfields/pull/61</a></p>

python django django-models django-geoposition