Opened 11 years ago
Closed 11 years ago
#21754 closed Bug (fixed)
Object discrepency between python2.x and python3.x with model field "to_python" and "get_prep_value" when retrieving object from database
Reported by: | Troy Grosfield | Owned by: | nobody |
---|---|---|---|
Component: | Python 3 | Version: | 1.6 |
Severity: | Normal | Keywords: | python3 |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I put together the following example to demonstrate the differences between python 2 and python 3 and how they handle coercing raw data into model objects when interacting with the db. Ignore the lame example, it's just to demonstrate the error with python 3.
Current setup:
- python2 test is using python 2.7.6
- python3 test is using python 3.3.3
- Using sqlite backend
# Model Field and model class IntStoredAsStringField(models.CharField): __metaclass__ = models.SubfieldBase def __init__(self, max_length=2000, *args, **kwargs): super(IntStoredAsStringField, self).__init__(max_length=max_length, *args, **kwargs) def to_python(self, value): if isinstance(value, int): return value return int(value) def get_prep_value(self, value): return smart_text(value) class SomeModel(models.Model): int_stored_as_string_field = IntStoredAsStringField()
# test class Py2To3ErrorTestCase(TestCase): def test_show_error(self): some_int = 5 obj = SomeModel(int_stored_as_string_field=some_int) obj.save() obj_db = SomeModel.objects.get(id=obj.id) # field "to_python" method gets called when retrieving the object # in python 2, doesn't in python 3 which causes this test to fail # in python 3. self.assertEqual(obj_db.int_stored_as_string_field, obj.int_stored_as_string_field)
Test output succeeds in python 2. In python 3 I see the following error:
====================================================================== FAIL: test_show_error (Py2To3ErrorTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "some/path/test_model_fields.py", line 150, in test_show_error obj.int_stored_as_string_field) AssertionError: '5' != 5
The field's "to_python(...)" method doesn't get called in python 3 like it does in python 2 when retrieving objects from the db. Am I missing something here?
Change History (2)
comment:1 by , 11 years ago
comment:2 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
That did the trick! Thanks @mjtamlyn! Here's the working change for the example above:
from django.utils.six import with_metaclass class IntStoredAsStringField(with_metaclass(models.SubfieldBase, models.CharField)): def __init__(self, max_length=2000, *args, **kwargs): super(IntStoredAsStringField, self).__init__(max_length=max_length, *args, **kwargs) def to_python(self, value): if isinstance(value, int): return value return int(value) def get_prep_value(self, value): return smart_text(value)
__metaclass__
does nothing on python 3. Can you try your example using http://pythonhosted.org/six/#six.with_metaclass?