After upgrading from Django 1.9
to 1.10
, I've experienced a change in behaviour with a field provided by the django-geolocation package.
This is the change that was made for 1.10
compatibility that broke the behaviour: https://github.com/philippbosch/django-geoposition/commit/689ff1651a858d81b2d82ac02625aae8a125b9c9
Previously, if you initialized a model with a GeopositionField
, and then immediately accessed that field, you would get back a Geoposition
object. Now you just get back the string value that you provided at initialization.
How do you achieve the same behaviour with Django 1.10
? Is there another method like from_db_value
that needs to be overridden to call to_python
?
Look at the existing Django fields (in django/db/models/fields/__init__.py ) for inspiration. Try to find a field that's similar to what you want and extend it a little bit, instead of creating an entirely new field from scratch. Put a __str__() method on the class you're wrapping up as a field.
To answer your question, with the new migration introduced in Django 1.7, in order to add a new field to a model you can simply add that field to your model and initialize migrations with ./manage.py makemigrations and then run ./manage.py migrate and the new field will be added to your DB.
Let's try to use required via Django Web application we created, visit http://localhost:8000/ and try to input the value based on option or validation applied on the Field. Hit submit. Hence Field is accepting the form even without any data in the geeks_field. This makes required=False implemented successfully.
Please select a fix: 1) Provide a one-off default now (will be set on all existing rows with a null value for this column) 2) Quit, and let me add a default in models.py Select an option: Then go to the Django project root folder in a terminal and run the command makemigrations. It will generate a new migration .
After lots of digging it turns out that in 1.8
the behaviour of custom fields was changed in such a way that to_python
is no longer called on assignment to a field.
https://docs.djangoproject.com/en/1.10/releases/1.8/#subfieldbase
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.
Here's a Django ticket with some more discussion on this change: https://code.djangoproject.com/ticket/26807
So in order to retain the old behaviour you need to do something like this:
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)
And then add this to the custom field:
def contribute_to_class(self, cls, name):
super(MyField, self).contribute_to_class(cls, name)
setattr(cls, name, CastOnAssignDescriptor(self))
Solution was taken from this pull request: https://github.com/hzdg/django-enumfields/pull/61
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With