diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index c1f6970..870ab04 100644
a
|
b
|
class AdminSite(object):
|
61 | 61 | they'll be applied as options to the admin class. |
62 | 62 | |
63 | 63 | If a model is already registered, this will raise AlreadyRegistered. |
| 64 | |
| 65 | If a model is abstract, this will raise ImproperlyConfigured. |
64 | 66 | """ |
65 | 67 | if not admin_class: |
66 | 68 | admin_class = ModelAdmin |
… |
… |
class AdminSite(object):
|
74 | 76 | if isinstance(model_or_iterable, ModelBase): |
75 | 77 | model_or_iterable = [model_or_iterable] |
76 | 78 | for model in model_or_iterable: |
| 79 | if model._meta.abstract: |
| 80 | raise ImproperlyConfigured('The model %s is abstract and ' |
| 81 | 'therefore cannot be registered' % model.__name__) |
| 82 | |
77 | 83 | if model in self._registry: |
78 | 84 | raise AlreadyRegistered('The model %s is already registered' % model.__name__) |
79 | 85 | |
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index 9ac99cc..bd3b956 100644
a
|
b
|
class CyclicTwo(models.Model):
|
641 | 641 | class Topping(models.Model): |
642 | 642 | name = models.CharField(max_length=20) |
643 | 643 | |
644 | | class Pizza(models.Model): |
| 644 | class AbstractPizza(models.Model): |
645 | 645 | name = models.CharField(max_length=20) |
| 646 | |
| 647 | class Meta: |
| 648 | abstract = True |
| 649 | |
| 650 | class Pizza(AbstractPizza): |
646 | 651 | toppings = models.ManyToManyField('Topping') |
647 | 652 | |
648 | 653 | class PizzaAdmin(admin.ModelAdmin): |
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index bbef907..a5cf305 100644
a
|
b
|
import urlparse
|
6 | 6 | |
7 | 7 | from django.conf import settings |
8 | 8 | from django.core import mail |
9 | | from django.core.exceptions import SuspiciousOperation |
| 9 | from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured |
10 | 10 | from django.core.files import temp as tempfile |
11 | 11 | from django.core.urlresolvers import reverse |
12 | 12 | # Register auth models with the admin. |
… |
… |
from models import (Article, BarAccount, CustomArticle, EmptyModel,
|
36 | 36 | Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, |
37 | 37 | Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee, |
38 | 38 | Question, Answer, Inquisition, Actor, FoodDelivery, |
39 | | RowLevelChangePermissionModel, Paper, CoverLetter) |
| 39 | RowLevelChangePermissionModel, Paper, CoverLetter, AbstractPizza) |
40 | 40 | |
41 | 41 | |
42 | 42 | class AdminViewBasicTest(TestCase): |
… |
… |
class CustomModelAdminTest(AdminViewBasicTest):
|
530 | 530 | response = self.client.get('/test_admin/%s/my_view/' % self.urlbit) |
531 | 531 | self.assert_(response.content == "Django is a magical pony!", response.content) |
532 | 532 | |
| 533 | class AdminRegistrationTest(TestCase): |
| 534 | |
| 535 | def testAbstractModel(self): |
| 536 | """ |
| 537 | Exception is raised when trying to register an abstract model. |
| 538 | Refs #12004. |
| 539 | """ |
| 540 | from django.contrib.admin import site |
| 541 | # Smoke test to determine whether admin site works at all |
| 542 | response = self.client.get('/test_admin/admin/admin_views/pizza/') |
| 543 | self.failUnlessEqual(response.status_code, 200) |
| 544 | self.assertRaises(ImproperlyConfigured, site.register, AbstractPizza) |
| 545 | |
533 | 546 | def get_perm(Model, perm): |
534 | 547 | """Return the permission object, for the Model""" |
535 | 548 | ct = ContentType.objects.get_for_model(Model) |