Reputation: 3037
I seem to have stumbled across a quirk in Django custom model fields. I have the following custom modelfield:
class PriceField(models.DecimalField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
try:
return Price(super(PriceField, self).to_python(value))
except (TypeError, AttributeError):
return None
def get_db_prep_value(self, value):
return super(PriceField, self).get_db_prep_value(value.d if value else value)
def value_to_string(self, instance):
return 'blah'
Which should always return the custom Price class in python. This works as expected:
>>> PricePoint.objects.all()[0].price
Price('1.00')
However when retrieving prices in the form of a values_list I get decimals back:
>>> PricePoint.objects.all().values_list('price')
[(Decimal('1'),)]
Then if I change the DB type to foat and try again I get a float:
>>> PricePoint.objects.all().values_list('price')
[(1.0,)]
>>> type(PricePoint.objects.all().values_list('price')[0][0])
<type 'float'>
This makes me think that values_list does not rely on to_python at all and instead just returns the type as defined in the database. Is that correct? Is there any way to return a custom type through values_list?
Upvotes: 4
Views: 745
Reputation: 577
Just to note that this was resolved in Django 1.8 with the addition of the from_db_value
method on custom fields.
See https://docs.djangoproject.com/en/1.8/howto/custom-model-fields/#converting-values-to-python-objects
Upvotes: 0
Reputation: 3037
Answered my own question: This apparently is a Django bug. values_list does not deserialize the database data.
It's being tracked here: https://code.djangoproject.com/ticket/9619 and is pending a design decision.
Upvotes: 3