Opened 12 years ago
Closed 12 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 , 12 years ago
comment:2 by , 12 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?