#19525 closed Bug (fixed)
Regression: FileField calls validate during form validation; breaks auto_now_add date fields
Reported by: | Russell Keith-Magee | Owned by: | Aymeric Augustin |
---|---|---|---|
Component: | File uploads/storage | Version: | 1.5-beta-1 |
Severity: | Release blocker | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
As of dcd43831 (fixing #9893), a FileField will call generate_filename()
as part of the validation step for a FileField on a form. This was then updated in 05d333ba to address #18515.
Unfortunately, this means that the filename function provided as an argument to upload_to can no longer reference any field with a pre-save behavior.
The common use case for this is to organize files on disk according to upload date. For example:
def user_filename(instance, filename): return os.path.join('user_files', instance.uploaded_timestamp.strftime('%Y-%m-%d'), filename) class UserFile(models.Model): uploaded_timestamp = models.DateTimeField(auto_now_add=True) data = models.FileField(upload_to=user_filename)
Under Django 1.5, attempting to call is_valid() on a Modelform for this model will raise a "'NoneType' object has no attribute 'strftime'" exception, because instance.uploaded_timestamp hasn't been instantiated yet. This is despite the fact that the uploaded data has been provided, the generated filename would be valid, and the upload timestamp can be computed.
In Django 1.4 and earlier, this works because no validation was performed for FileFields filenames; the uploaded_timestamp was evaluated as part of the model pre-save, and the persistence of the file to disk occurred after the model was saved.
To my reading, the documentation is ambiguous on whether this is expected behavior or not. It says that the model may not be saved to the database yet, but points at AutoField as the cause for problems. However, it also explicitly talks about using strftime as part of file paths. A file datetimes of 'now' would seem to be an obvious usage of this feature.
Change History (7)
comment:1 by , 12 years ago
comment:2 by , 12 years ago
Would this work if the DateTimeField
was declared with default=timezone.now
rather than auto_now_add=True
?
comment:3 by , 12 years ago
@aaugustin: I've just checked with my production code, and yes, default=timezone.now works for the auto_now_add case. However, it won't address auto_now, or the pre_save conflict problem.
comment:4 by , 12 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
Since we're extremely close to 1.5 RC1, the most reasonable course of action in the short term is to revert the two commits.
comment:5 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
For the record, I discovered this by upgrading a commercial project to Django 1.5, so there is at least one project in the wild that will be affected by this change. Although I've discovered it with a auto_now_add FileField, it's not hard to see that this change also affects any field with a pre_save behaviour.
It also has the potential to lead to incorrect validation. Consider the case of a field with a pre_save behavior that updates the field (auto_now is one example, but any denormalization/summary field would be an example). The call to validate occurs *before* the call to pre_save is made, which means that you're going to get the pre_save value used as part of your validation. If you then save the model, the pre_save() will be called, and the actual filename that is used for saving the file will be different to the one used for validation.
Some initial thoughts about possible solutions: