Opened 4 years ago

Closed 3 years ago

#19364 closed Bug (invalid)

Wrong exception raised at django/db/models/fields/related.py:343? (DoesNotExist instead of AttributeError)

Reported by: lbragues@… 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 Changed 4 years ago by lbragues@…

Owner: changed from nobody to lbragues

comment:2 Changed 4 years ago by lbragues

Cc: lbragues added

comment:3 Changed 4 years ago by Anssi Kääriäinen

Component: Database layer (models, ORM)Documentation
Triage Stage: UnreviewedAccepted

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. Hence DoesNotExist.

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.

comment:4 Changed 4 years ago by lbragues

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 Changed 4 years ago by Tim Graham

Has patch: unset

comment:6 Changed 4 years ago by Tim Graham

@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 Changed 4 years ago by boromil

Owner: changed from lbragues to anonymous
Status: newassigned

comment:8 Changed 4 years ago by anonymous

Owner: anonymous deleted
Status: assignednew

comment:9 Changed 3 years ago by Tim Graham

Resolution: invalid
Status: newclosed
Note: See TracTickets for help on using tickets.
Back to Top