Opened 3 years ago

Closed 2 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 3 years ago by lbragues@…

  • Needs documentation unset
  • Needs tests unset
  • Owner changed from nobody to lbragues
  • Patch needs improvement unset

comment:2 Changed 3 years ago by lbragues

  • Cc lbragues added

comment:3 Changed 3 years ago by akaariai

  • Component changed from Database layer (models, ORM) to Documentation
  • Triage Stage changed from Unreviewed to Accepted

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 3 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 3 years ago by timo

  • Has patch unset

comment:6 Changed 2 years ago by timo

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

  • Owner changed from lbragues to anonymous
  • Status changed from new to assigned

comment:8 Changed 2 years ago by anonymous

  • Owner anonymous deleted
  • Status changed from assigned to new

comment:9 Changed 2 years ago by timo

  • Resolution set to invalid
  • Status changed from new to closed
Note: See TracTickets for help on using tickets.
Back to Top