Opened 12 years ago
Closed 11 years ago
#19364 closed Bug (invalid)
Wrong exception raised at django/db/models/fields/related.py:343? (DoesNotExist instead of AttributeError)
Reported by: | Owned by: | ||
---|---|---|---|
Component: | Documentation | Version: | 1.4 |
Severity: | Normal | Keywords: | DoesNotExist, django.db, getattr, |
Cc: | lbragues | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
My problem is at the admin models when calling a getattr from the save_module function using the object being saved, instead of returning the default value it raises a DoesNotExist exception, failing the python manual specification for getattr.
I'm wondering if the exception thrown shouldn't be AttributeError instead of DoesNotExist...
If I make a getattr call to that object and that exception is thrown my program will exit instead of being catched by the getattr method and the default value returned.
Reproducing:
models.py
class GroupProperty(models.Model): CHOICES = ( ('disk_quota','Disk Quota'), ('n_backups','Number of Backups'), ) group = models.ForeignKey(Group) key = models.CharField(max_length=200,choices=CHOICES) value = models.CharField(max_length=200) start = models.DateTimeField() end = models.DateTimeField() description = models.TextField() author = models.ForeignKey(User) edit = models.DateTimeField(default=datetime.now()) creation = models.DateTimeField(default=datetime.now()) # na alteracao actualiza data def save(self): self.edit = datetime.now() super(GroupProperty, self).save() class Meta: verbose_name_plural = "Group Properties"
admin.py
class GroupPropertyAdmin(admin.ModelAdmin): fieldsets = [ (None, {'fields': ['group','key','value','start','end',"description"]}), ('Auto generated fields', {'fields':['author','edit','creation']}) ] list_display = ('group', 'key','value','start','end') readonly_fields = ('edit','author','creation') list_filter = ['key','group'] search_fields = ['key','value','group','description'] ordering = ('-creation',) def save_model(self, request, obj, form, change): #Error here if getattr(obj, 'author', 'None') is 'None': obj.author = request.user obj.save() admin.site.register(GroupProperty, GroupPropertyAdmin)
Django stacktrace:
Environment: Request Method: POST Request URL: http://localhost:8080/admin/core/groupproperty/add/ Django Version: 1.4.2 Python Version: 2.7.3 Installed Applications: ('django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.admin', '*****.core') Installed Middleware: ('django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware') Traceback: File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/core/handlers/base.py" in get_response 111. response = callback(request, *callback_args, **callback_kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/contrib/admin/options.py" in wrapper 366. return self.admin_site.admin_view(view)(*args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/utils/decorators.py" in _wrapped_view 91. response = view_func(request, *args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/views/decorators/cache.py" in _wrapped_view_func 89. response = view_func(request, *args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/contrib/admin/sites.py" in inner 196. return view(request, *args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/utils/decorators.py" in _wrapper 25. return bound_func(*args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/utils/decorators.py" in _wrapped_view 91. response = view_func(request, *args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/utils/decorators.py" in bound_func 21. return func(self, *args2, **kwargs2) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/db/transaction.py" in inner 209. return func(*args, **kwargs) File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/contrib/admin/options.py" in add_view 955. self.save_model(request, new_object, form, False) File "/home/someone/folder/to/project/****/core/admin.py" in save_model 36. if getattr(obj, 'author', 'None') is 'None': File "/usr/local/lib/python2.7/dist-packages/Django-1.4.2-py2.7.egg/django/db/models/fields/related.py" in __get__ 343. raise self.field.rel.to.DoesNotExist Exception Type: DoesNotExist at /admin/core/groupproperty/add/ Exception Value:
Change History (9)
comment:1 by , 12 years ago
Owner: | changed from | to
---|
comment:2 by , 12 years ago
Cc: | added |
---|
comment:3 by , 12 years ago
Component: | Database layer (models, ORM) → Documentation |
---|---|
Triage Stage: | Unreviewed → Accepted |
comment:4 by , 12 years ago
Then by throwing DoesNotExist we can't simply do a getattr call to check if the attribute exists in the db and if it has a value assigned, since DoesNotExists isn't catched by getattr.
It goes a little bit against what you expect python to do from reading the python docs http://docs.python.org/3/library/functions.html#getattr (docs v2 is equal).
And also if you do a dir(obj) the output shows that the object as a property with the name you are trying to get, so it can be a little confusing at first...
So the solution I adopted to do this is to try...except:
try: #do something with object except DosNotExist: #do something on exception
comment:5 by , 12 years ago
Has patch: | unset |
---|
comment:6 by , 12 years ago
@akaariai, is the example with the text "p2 doesn't have an associated restaurant" what you're looking for?
https://docs.djangoproject.com/en/dev/topics/db/examples/one_to_one/
comment:7 by , 11 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:8 by , 11 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:9 by , 11 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
The
DoesNotExist
is how relations work in Django. The attribute isn't missing. Getting the value for the attribute doesn't succeed as nothing exists for that attribute in the DB. HenceDoesNotExist
.For some reason I can't find the this from the documentation. Seems somewhat surprising if this isn't documented...
I am leaving this open so that we can confirm that this is documented somewhere.