In the below model I have a custom field FooField which always returns
"foo" as the value to be stored but when I create an object with another
value say 'a' it only has the value 'a' stored in the returned object. I
need to do a refresh_from_db to clear the wrong value and to fetch the
correct value. I couldn't find this documented at
[https://docs.djangoproject.com/en/2.0/howto/custom-model-fields/]. If
this an expected behavior adding a note in the documentation will be of
help.
models.py
{{{
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class FooField(models.CharField):
def to_python(self, value):
value = super(self.__class__, self).to_python(value)
return "foo"
def get_prep_value(self, value):
value = super(self.__class__, self).get_prep_value(value)
return "foo"
class FooBase(models.Model):
base_field = models.CharField(max_length=120)
class Foo(FooBase):
custom_field = FooField(max_length=120)
}}}
Shell session
{{{
In [11]: bar = Foo.objects.create(base_field='1', custom_field='a')
In [12]: bar.custom_field
Out[12]: 'a'
In [13]: bar.refresh_from_db()
In [14]: bar.custom_field
Out[14]: 'foo'
In [15]: bar.id
Out[15]: 10
}}}
{{{
sqlite> select * from TestApp_foo;
10|foo
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/29173>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* type: Bug => Cleanup/optimization
* stage: Unreviewed => Accepted
* component: Database layer (models, ORM) => Documentation
Comment:
I think that's expected behavior as it would add non-trivial overhead to
refresh fields from the database after each `save()`. There might be a
hook that would allow you to do that for your custom field.
--
Ticket URL: <https://code.djangoproject.com/ticket/29173#comment:1>
Comment (by Xtreak):
Replying to [comment:1 Tim Graham]:
> I think that's expected behavior as it would add non-trivial overhead to
refresh fields from the database after each `save()`. There might be a
hook that would allow you to do that for your custom field.
I think we don't need to refresh the value from db. Since we know during
`get_prep_value` function call the value to be inserted in the database
and we can update the object with the correct value which is inserted at
[https://github.com/django/django/blob/a2e97abd8149e78071806a52282a24c27fe8236b/django/db/models/sql/compiler.py#L1217].
I might be wrong here due to my limited knowledge of ORM.
However I also think it's a breaking change and it will be good to make a
note of this behavior in the documentation than to make this code change.
Thanks for all the work.
--
Ticket URL: <https://code.djangoproject.com/ticket/29173#comment:2>
* status: new => closed
* resolution: => invalid
Comment:
The ''Custom Model Fields'' How-To discusses this usage explicitly in the
[https://docs.djangoproject.com/en/2.0/howto/custom-model-fields
/#preprocessing-values-before-saving Preprocessing values before saving]
section.
It suggests using `pre_save(model_instance, add)` for this kind of
behaviour.
It explicitly makes updating the model's attribute the user's
responsibility:
> You should also update the model’s attribute if you make any changes to
the value so that code holding references to the model will always see the
correct value.
Note `pre_save` takes the `model_instance` parameter precisely for this
purpose.
The canonical example of this usage is from `DateTimeField`, for handling
`auto_now` and `auto_now_add`:
{{{
def pre_save(self, model_instance, add):
if self.auto_now or (self.auto_now_add and add):
value = datetime.date.today()
setattr(model_instance, self.attname, value)
return value
else:
return super().pre_save(model_instance, add)
}}}
The quoted line from the docs was
[https://github.com/django/django/commit/8216abe74889cc867a4cf89e6708f37cec6b2e72
introduced in 2007] so this behaviour (and expected usage) is part of the
original design of the `Field` API. As such I'm going to close this
ticket.
--
Ticket URL: <https://code.djangoproject.com/ticket/29173#comment:3>