From 1089bda54600b55a73f09c53c9b6dcee2f197b17 Mon Sep 17 00:00:00 2001 From: Joseph Kocherhans Date: Wed, 24 Feb 2010 14:32:11 +0000 Subject: [PATCH] Fixed #12152. DoesNotExist and MultipleObjectsReturned now subclass their parent model's exceptions. Thanks, mattmcc and Alex Gaynor. git-svn-id: http://code.djangoproject.com/svn/django/trunk@12567 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/base.py | 20 ++++++---- tests/modeltests/model_inheritance/models.py | 41 ++++++++++++++++++++ tests/modeltests/proxy_models/models.py | 20 ++++++++++ 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/django/db/models/base.py b/django/db/models/base.py index 449c41a3b4..4ed402f437 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -52,10 +52,14 @@ class ModelBase(type): new_class.add_to_class('_meta', Options(meta, **kwargs)) if not abstract: - new_class.add_to_class('DoesNotExist', - subclass_exception('DoesNotExist', ObjectDoesNotExist, module)) - new_class.add_to_class('MultipleObjectsReturned', - subclass_exception('MultipleObjectsReturned', MultipleObjectsReturned, module)) + new_class.add_to_class('DoesNotExist', subclass_exception('DoesNotExist', + tuple(x.DoesNotExist + for x in parents if hasattr(x, '_meta') and not x._meta.abstract) + or (ObjectDoesNotExist,), module)) + new_class.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned', + tuple(x.MultipleObjectsReturned + for x in parents if hasattr(x, '_meta') and not x._meta.abstract) + or (MultipleObjectsReturned,), module)) if base_meta and not base_meta.abstract: # Non-abstract child classes inherit some attributes from their # non-abstract parent (unless an ABC comes before it in the @@ -919,8 +923,8 @@ model_unpickle.__safe_for_unpickle__ = True if sys.version_info < (2, 5): # Prior to Python 2.5, Exception was an old-style class - def subclass_exception(name, parent, unused): - return types.ClassType(name, (parent,), {}) + def subclass_exception(name, parents, unused): + return types.ClassType(name, parents, {}) else: - def subclass_exception(name, parent, module): - return type(name, (parent,), {'__module__': module}) + def subclass_exception(name, parents, module): + return type(name, parents, {'__module__': module}) diff --git a/tests/modeltests/model_inheritance/models.py b/tests/modeltests/model_inheritance/models.py index 36fc9fef1b..95bf5abf99 100644 --- a/tests/modeltests/model_inheritance/models.py +++ b/tests/modeltests/model_inheritance/models.py @@ -38,6 +38,9 @@ class Student(CommonInfo): class Meta: pass +class StudentWorker(Student, Worker): + pass + # # Abstract base classes with related models # @@ -176,6 +179,32 @@ Traceback (most recent call last): ... AttributeError: type object 'CommonInfo' has no attribute 'objects' +# A StudentWorker which does not exist is both a Student and Worker which does not exist. +>>> try: +... StudentWorker.objects.get(id=1) +... except Student.DoesNotExist: +... pass +>>> try: +... StudentWorker.objects.get(id=1) +... except Worker.DoesNotExist: +... pass + +# MultipleObjectsReturned is also inherited. +>>> sw1 = StudentWorker() +>>> sw1.name = 'Wilma' +>>> sw1.age = 35 +>>> sw1.save() +>>> sw2 = StudentWorker() +>>> sw2.name = 'Betty' +>>> sw2.age = 34 +>>> sw2.save() +>>> try: +... StudentWorker.objects.get(id__lt=10) +... except Student.MultipleObjectsReturned: +... pass +... except Worker.MultipleObjectsReturned: +... pass + # Create a Post >>> post = Post(title='Lorem Ipsum') >>> post.save() @@ -267,6 +296,18 @@ Traceback (most recent call last): ... DoesNotExist: ItalianRestaurant matching query does not exist. +# An ItalianRestaurant which does not exist is also a Place which does not exist. +>>> try: +... ItalianRestaurant.objects.get(name='The Noodle Void') +... except Place.DoesNotExist: +... pass + +# MultipleObjectsReturned is also inherited. +>>> try: +... Restaurant.objects.get(id__lt=10) +... except Place.MultipleObjectsReturned: +... pass + # Related objects work just as they normally do. >>> s1 = Supplier(name="Joe's Chickens", address='123 Sesame St') diff --git a/tests/modeltests/proxy_models/models.py b/tests/modeltests/proxy_models/models.py index 44fee9ee6c..49972f3d2c 100644 --- a/tests/modeltests/proxy_models/models.py +++ b/tests/modeltests/proxy_models/models.py @@ -206,6 +206,26 @@ False >>> MyPersonProxy.objects.all() [, , ] +# Proxy models are included in the ancestors for a model's DoesNotExist and MultipleObjectsReturned +>>> try: +... MyPersonProxy.objects.get(name='Zathras') +... except Person.DoesNotExist: +... pass +>>> try: +... MyPersonProxy.objects.get(id__lt=10) +... except Person.MultipleObjectsReturned: +... pass +>>> try: +... StatusPerson.objects.get(name='Zathras') +... except Person.DoesNotExist: +... pass +>>> sp1 = StatusPerson.objects.create(name='Bazza Jr.') +>>> sp2 = StatusPerson.objects.create(name='Foo Jr.') +>>> try: +... StatusPerson.objects.get(id__lt=10) +... except Person.MultipleObjectsReturned: +... pass + # And now for some things that shouldn't work... # # All base classes must be non-abstract