This is expected behavior, and was a design decision, as is written in ticket #12401:
Model attributes are not converted to the correct Python types when you set the attribute. That's the design decision we made, and one that isn't going to change without a lot of backwards incompatibilities.
This is thus expected behavior for (almost) all Fields, although one can, strictly speaking use the __get__ and __set__ methods to change that behavior (or use other techniques like metaclasses), so strictly speaking it is possible to add such behavior.
After all, you just set an attribute of a Python object, and that object happens to be a Python object. It is only when writing to the database, etc. that these attributes are converted to their corresponding database type and vice versa. In some scenario's that means if you store a value of one type in an object, if you store it in the database, and later retrieve the same object, that attribute has another type.
It however makes sense not to perform such conversions since, like the comment ticket #12401 mentions:
In general, I expect to the following to pass, no matter what foo
is:
>>> x = '2011-06-06'
>>> foo.bar = x
>>> assert foo.bar == x
The proposed behaviour, though potentially useful or even better for
Django model objects, would certainly violate that expectation, so
the design decision we've made is certainly sensible.