Opened 10 years ago
Last modified 7 years ago
#24823 new Bug
FileField with callable default raises error with forms
Reported by: | Haussonne Yves-Marie | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.8 |
Severity: | Normal | Keywords: | FileField, models, field, callable, default, form |
Cc: | real.human@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Hello,
When a FileField has a callable default value, the following error is raised when a new object is created using a form and no value is provided for the field:
'function' object has no attribute '_committed' in db/models/fields/files.py in pre_save, line 316
This bug can be reproduced with the content of the following gist : https://gist.github.com/ymph/cd2b684f3f2f38a680d5 and by following the instruction in the README.
The problem does not appear when creating the object without forms.
I was able to naively "correct" the problem by adding the following lines in the file db/models/fields/files.py, line 194 in FileDescriptor.__get__:
if callable(file): file = file()
here is a complete traceback:
Environment: Request Method: POST Request URL: http://localhost:8000/admin/testdefault/testobject/add/ Django Version: 1.8.1 Python Version: 2.7.6 Installed Applications: ('django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'testdefault') Installed Middleware: ('django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware') Traceback: File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 132. response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper 616. return self.admin_site.admin_view(view)(*args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view 110. response = view_func(request, *args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func 57. response = view_func(request, *args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner 233. return view(request, *args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/contrib/admin/options.py" in add_view 1516. return self.changeform_view(request, None, form_url, extra_context) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper 34. return bound_func(*args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view 110. response = view_func(request, *args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func 30. return func.__get__(self, type(self))(*args2, **kwargs2) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/utils/decorators.py" in inner 145. return func(*args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/contrib/admin/options.py" in changeform_view 1467. self.save_model(request, new_object, form, not add) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/contrib/admin/options.py" in save_model 1078. obj.save() File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/base.py" in save 710. force_update=force_update, update_fields=update_fields) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/base.py" in save_base 738. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/base.py" in _save_table 822. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/base.py" in _do_insert 861. using=using, raw=raw) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/manager.py" in manager_method 127. return getattr(self.get_queryset(), name)(*args, **kwargs) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/query.py" in _insert 920. return query.get_compiler(using=using).execute_sql(return_id) File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql 970. for sql, params in self.as_sql(): File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in as_sql 928. for obj in self.query.objs File "/Users/ymh/dev/venvs/testdefault/lib/python2.7/site-packages/django/db/models/fields/files.py" in pre_save 316. if file and not file._committed: Exception Type: AttributeError at /admin/testdefault/testobject/add/ Exception Value: 'function' object has no attribute '_committed'
regards.
Change History (8)
comment:1 by , 10 years ago
Description: | modified (diff) |
---|
comment:2 by , 10 years ago
comment:3 by , 10 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Currently the behavior of how default
should work on FileField
isn't well defined (see #17224). Let's address that one first and then reopen this if we decide it makes sense to support this. By the way, any patch should be against the master branch, as this wouldn't be backported to 1.8. Thanks!
comment:4 by , 8 years ago
Just spent a few hours stepping through tracebacks trying to find out exactly what Django is doing here, before coming to the conclusion that it must be a Django bug and searching for an existing ticket.
Perhaps I haven't read the documentation recently or thoroughly enough, but they don't seem that ambiguous regarding the behaviour of default
specifically:
The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created.
There's no special caveat for FileField
and ImageField
saying that callables cannot be used.
Whether or not additional special handling of the evaluated default value (as per discussion on #17224) is ever implemented, that should not make any difference at all as to whether or not a callable can be used as a default.
I think this ticket should be re-opened, and can and should be resolved much quicker and simpler than #17224, without much debate?
It's valid to assign a string to a FileField
(on an instance, or as a default value). Is there any reason why a callable that returns a string shouldn't be valid?
comment:5 by , 8 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
comment:6 by , 8 years ago
Keywords: | callable default form added |
---|
Plus, the fact that this actually does work as expected for FileField
(models) is *only* broken with forms, makes the case stronger that this is a clear bug. The forms docs even say (of Field.initial
):
Instead of a constant, you can also pass any callable
And when we stepped through form cleaning, we noticed that form data *did* contain a properly evaluated default as initial-{fieldname}
, but the field cleaning ignored it and assigned the raw callable from the model instead.
comment:7 by , 8 years ago
Cc: | added |
---|
comment:8 by , 7 years ago
Summary: | FileField with callable default raise error with forms → FileField with callable default raises error with forms |
---|---|
Triage Stage: | Unreviewed → Accepted |
Hello,
a attempt for a correction can be found in the branch ticket_24823 of my fork : https://github.com/IRI-Research/django/tree/ticket_24823
regards,
ymph