Opened 15 years ago
Closed 13 years ago
#12401 closed Bug (invalid)
DateField/DateTimeField is not instantiated with Python datetime.date/datetime object until after retrieving from the database
Reported by: | heidar_rafn | Owned by: | nobody |
---|---|---|---|
Component: | Core (Other) | Version: | 1.1 |
Severity: | Normal | Keywords: | DateField DateTimeField |
Cc: | jroesslein@… | Triage Stage: | Design decision needed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The Django documentation states:
" DateField
class DateField([auto_now=False, auto_now_add=False, options])
A date, represented in Python by a datetime.date instance..."
I have experienced a problem with this - the field is not represented by the datetime.date class until after retrived from the database.
Here is a small example that shows this:
class chgLog(models.Model): chgReason = models.CharField(max_length=255) validFrom = models.DateField()
Following is from a Python/Django shell session :
>>> chglog = chgLog(chgReason='testing datefield',validFrom='2009-13-43') >>> chglog.id >>> chglog.validFrom '2009-13-43' >>> chglog.validFrom.__class__ <type 'str'> >>> chglog.save() Traceback (most recent call last): File "<console>", line 1, in <module> File "/usr/lib/pymodules/python2.6/django/db/models/base.py", line 410, in save self.save_base(force_insert=force_insert, force_update=force_update) File "/usr/lib/pymodules/python2.6/django/db/models/base.py", line 483, in save_base values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)] File "/usr/lib/pymodules/python2.6/django/db/models/fields/__init__.py", line 192, in get_db_prep_save return self.get_db_prep_value(value) File "/usr/lib/pymodules/python2.6/django/db/models/fields/__init__.py", line 511, in get_db_prep_value return connection.ops.value_to_db_date(self.to_python(value)) File "/usr/lib/pymodules/python2.6/django/db/models/fields/__init__.py", line 484, in to_python raise exceptions.ValidationError(msg) ValidationError: Invalid date: month must be in 1..12
It shows that validation is done properly.
Now let us have all values valid:
>>> chglog = chgLog(chgReason='testing datefield',validFrom='2009-12-18') >>> chglog.id >>> chglog.validFrom '2009-12-18' >>> chglog.validFrom.__class__ <type 'str'> >>> chglog.save() >>> chglog.id 130L >>> chglog.validFrom '2009-12-18' >>> chglog.validFrom.__class__ <type 'str'>
And here it is obvious that the object stores the DateField as string, even after saving.
Now let us investigate it after retrieving it from the database:
>>> chglog_from_db = chgLog.objects.get(id=130) >>> chglog_from_db.id 130L >>> chglog_from_db.validFrom datetime.date(2009, 12, 18) >>> chglog_from_db.validFrom.__class__ <type 'datetime.date'>
And finally this code segments that compares DateField from two different Django objects, the first one after saving, the second one after retrieving from the database. Same object (2 copies), but reported to have different values:
>>> chglog.validFrom == chglog_from_db.validFrom False >>>
Change History (10)
comment:1 by , 15 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
comment:2 by , 15 years ago
Cc: | added |
---|---|
Summary: | DateField is not instantiated with Python datetime.date object until after retrieving from the database → DateField/DateTimeField is not instantiated with Python datetime.date/datetime object until after retrieving from the database |
comment:3 by , 15 years ago
Keywords: | DateTimeField added |
---|
follow-up: 6 comment:5 by , 15 years ago
follow-up: 7 comment:6 by , 15 years ago
Replying to josh:
Replying to JohnDoe:
See ticket #12223, there's no validation on Models.
What does this issue have to do with validation?
Well, try using a ModelForm instead of working directly on models like that, you'll see that a form converts it into a datetime object.
Which brings me to my validation point, Models does nothing but bare minimum to get it saved, Forms does validation and conversion.
comment:7 by , 15 years ago
Replying to JohnDoe:
Replying to josh:
Replying to JohnDoe:
See ticket #12223, there's no validation on Models.
What does this issue have to do with validation?
Well, try using a ModelForm instead of working directly on models like that, you'll see that a form converts it into a datetime object.
Which brings me to my validation point, Models does nothing but bare minimum to get it saved, Forms does validation and conversion.
As I pointed out in this ticket, a validation on the Date field is performed on saving (it does not save invalid date).
Therefore the statement that models do not validate is not absolutely true.
I pointed out in my last point in the ticket, that after saving the model, it is in different form when retrived from the database - and that was my main point with this ticket and it made me wonder whether Django is as perfect as I have found it so far.
comment:8 by , 15 years ago
Replying to heidar_rafn:
Replying to JohnDoe:
Replying to josh:
Replying to JohnDoe:
See ticket #12223, there's no validation on Models.
What does this issue have to do with validation?
Well, try using a ModelForm instead of working directly on models like that, you'll see that a form converts it into a datetime object.
Which brings me to my validation point, Models does nothing but bare minimum to get it saved, Forms does validation and conversion.
As I pointed out in this ticket, a validation on the Date field is performed on saving (it does not save invalid date).
Therefore the statement that models do not validate is not absolutely true.
I pointed out in my last point in the ticket, that after saving the model, it is in different form when retrived from the database - and that was my main point with this ticket and it made me wonder whether Django is as perfect as I have found it so far.
You just need to understand how things really work (and if you look at the other ticket, you'll see i argued like you're doing, mostly because it seems undocumented. Your ticket supports my original point).
This is the best example i can come up with on the spot.
Use SQLite which does not enforce datatypes ect.
The Setup:
class Test(models.Model): text = models.CharField(max_length=10)
The Test:
>>> t = Test() >>> t.text = '0123456789horse' >>> t.save() >>> y = Test.objects.all() >>> y[0].text u'0123456789horse'
This discussion should probably be moved to the mailinglist if it should be discussed further, as it is not a bug, but merely a design discussion.
comment:9 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → Bug |
comment:10 by , 13 years ago
Easy pickings: | unset |
---|---|
Resolution: | → invalid |
Status: | new → closed |
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. It is consistent with normal Python behaviour - it would be rare for type checking to occur when attributes are set, and even rarer for type conversion to occur. 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.
The DateTimeField is also affected.
One way to get around this issue is to initialize the value with a datetime.date object
instead of using a string. Example:
Changing save() to convert the strings to datetime types might break apps that expect
the type to not change. If we choose not to fix this this behaviour should at least be documented.