PageRenderTime 391ms CodeModel.GetById 81ms app.highlight 249ms RepoModel.GetById 52ms app.codeStats 1ms

/tests/regressiontests/modeladmin/tests.py

https://code.google.com/p/mango-py/
Python | 1229 lines | 1179 code | 31 blank | 19 comment | 23 complexity | 5cebef191ea22a3051e7e3379bd30052 MD5 | raw file
   1from datetime import date
   2
   3from django import forms
   4from django.conf import settings
   5from django.contrib.admin.options import ModelAdmin, TabularInline, \
   6    HORIZONTAL, VERTICAL
   7from django.contrib.admin.sites import AdminSite
   8from django.contrib.admin.validation import validate
   9from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect
  10from django.core.exceptions import ImproperlyConfigured
  11from django.forms.models import BaseModelFormSet
  12from django.forms.widgets import Select
  13from django.test import TestCase
  14from django.utils import unittest
  15
  16from models import Band, Concert, ValidationTestModel, \
  17    ValidationTestInlineModel
  18
  19
  20# None of the following tests really depend on the content of the request,
  21# so we'll just pass in None.
  22request = None
  23
  24
  25class ModelAdminTests(TestCase):
  26
  27    def setUp(self):
  28        self.band = Band.objects.create(
  29            name='The Doors',
  30            bio='',
  31            sign_date=date(1965, 1, 1),
  32        )
  33        self.site = AdminSite()
  34
  35    # form/fields/fieldsets interaction ##############################
  36
  37    def test_default_fields(self):
  38        ma = ModelAdmin(Band, self.site)
  39
  40        self.assertEqual(ma.get_form(request).base_fields.keys(),
  41            ['name', 'bio', 'sign_date'])
  42
  43    def test_default_fieldsets(self):
  44        # fieldsets_add and fieldsets_change should return a special data structure that
  45        # is used in the templates. They should generate the "right thing" whether we
  46        # have specified a custom form, the fields argument, or nothing at all.
  47        #
  48        # Here's the default case. There are no custom form_add/form_change methods,
  49        # no fields argument, and no fieldsets argument.
  50        ma = ModelAdmin(Band, self.site)
  51        self.assertEqual(ma.get_fieldsets(request),
  52            [(None, {'fields': ['name', 'bio', 'sign_date']})])
  53
  54        self.assertEqual(ma.get_fieldsets(request, self.band),
  55            [(None, {'fields': ['name', 'bio', 'sign_date']})])
  56
  57    def test_field_arguments(self):
  58        # If we specify the fields argument, fieldsets_add and fielsets_change should
  59        # just stick the fields into a formsets structure and return it.
  60        class BandAdmin(ModelAdmin):
  61             fields = ['name']
  62
  63        ma = BandAdmin(Band, self.site)
  64
  65        self.assertEqual( ma.get_fieldsets(request),
  66            [(None, {'fields': ['name']})])
  67
  68        self.assertEqual(ma.get_fieldsets(request, self.band),
  69            [(None, {'fields': ['name']})])
  70
  71    def test_field_arguments_restricted_on_form(self):
  72        # If we specify fields or fieldsets, it should exclude fields on the Form class
  73        # to the fields specified. This may cause errors to be raised in the db layer if
  74        # required model fields arent in fields/fieldsets, but that's preferable to
  75        # ghost errors where you have a field in your Form class that isn't being
  76        # displayed because you forgot to add it to fields/fieldsets
  77
  78        # Using `fields`.
  79        class BandAdmin(ModelAdmin):
  80            fields = ['name']
  81
  82        ma = BandAdmin(Band, self.site)
  83        self.assertEqual(ma.get_form(request).base_fields.keys(), ['name'])
  84        self.assertEqual(ma.get_form(request, self.band).base_fields.keys(),
  85            ['name'])
  86
  87        # Using `fieldsets`.
  88        class BandAdmin(ModelAdmin):
  89            fieldsets = [(None, {'fields': ['name']})]
  90
  91        ma = BandAdmin(Band, self.site)
  92        self.assertEqual(ma.get_form(request).base_fields.keys(), ['name'])
  93        self.assertEqual(ma.get_form(request, self.band).base_fields.keys(),
  94            ['name'])
  95
  96        # Using `exclude`.
  97        class BandAdmin(ModelAdmin):
  98            exclude = ['bio']
  99
 100        ma = BandAdmin(Band, self.site)
 101        self.assertEqual(ma.get_form(request).base_fields.keys(),
 102            ['name', 'sign_date'])
 103
 104        # You can also pass a tuple to `exclude`.
 105        class BandAdmin(ModelAdmin):
 106            exclude = ('bio',)
 107
 108        ma = BandAdmin(Band, self.site)
 109        self.assertEqual(ma.get_form(request).base_fields.keys(),
 110            ['name', 'sign_date'])
 111
 112        # Using `fields` and `exclude`.
 113        class BandAdmin(ModelAdmin):
 114            fields = ['name', 'bio']
 115            exclude = ['bio']
 116
 117        ma = BandAdmin(Band, self.site)
 118        self.assertEqual(ma.get_form(request).base_fields.keys(),
 119            ['name'])
 120
 121    def test_custom_form_validation(self):
 122        # If we specify a form, it should use it allowing custom validation to work
 123        # properly. This won't, however, break any of the admin widgets or media.
 124
 125        class AdminBandForm(forms.ModelForm):
 126            delete = forms.BooleanField()
 127
 128            class Meta:
 129                model = Band
 130
 131        class BandAdmin(ModelAdmin):
 132            form = AdminBandForm
 133
 134        ma = BandAdmin(Band, self.site)
 135        self.assertEqual(ma.get_form(request).base_fields.keys(),
 136            ['name', 'bio', 'sign_date', 'delete'])
 137
 138        self.assertEqual(
 139            type(ma.get_form(request).base_fields['sign_date'].widget),
 140            AdminDateWidget)
 141
 142    def test_queryset_override(self):
 143        # If we need to override the queryset of a ModelChoiceField in our custom form
 144        # make sure that RelatedFieldWidgetWrapper doesn't mess that up.
 145
 146        band2 = Band(name='The Beatles', bio='', sign_date=date(1962, 1, 1))
 147        band2.save()
 148
 149        class ConcertAdmin(ModelAdmin):
 150            pass
 151        ma = ConcertAdmin(Concert, self.site)
 152        form = ma.get_form(request)()
 153
 154        self.assertEqual(str(form["main_band"]),
 155            '<select name="main_band" id="id_main_band">\n'
 156            '<option value="" selected="selected">---------</option>\n'
 157            '<option value="%d">The Beatles</option>\n'
 158            '<option value="%d">The Doors</option>\n'
 159            '</select>' % (band2.id, self.band.id))
 160
 161        class AdminConcertForm(forms.ModelForm):
 162            class Meta:
 163                model = Concert
 164
 165            def __init__(self, *args, **kwargs):
 166                super(AdminConcertForm, self).__init__(*args, **kwargs)
 167                self.fields["main_band"].queryset = Band.objects.filter(name='The Doors')
 168
 169        class ConcertAdmin(ModelAdmin):
 170            form = AdminConcertForm
 171
 172        ma = ConcertAdmin(Concert, self.site)
 173        form = ma.get_form(request)()
 174
 175        self.assertEqual(str(form["main_band"]),
 176            '<select name="main_band" id="id_main_band">\n'
 177            '<option value="" selected="selected">---------</option>\n'
 178            '<option value="%d">The Doors</option>\n'
 179            '</select>' % self.band.id)
 180
 181    # radio_fields behavior ###########################################
 182
 183    def test_default_foreign_key_widget(self):
 184        # First, without any radio_fields specified, the widgets for ForeignKey
 185        # and fields with choices specified ought to be a basic Select widget.
 186        # ForeignKey widgets in the admin are wrapped with RelatedFieldWidgetWrapper so
 187        # they need to be handled properly when type checking. For Select fields, all of
 188        # the choices lists have a first entry of dashes.
 189
 190        cma = ModelAdmin(Concert, self.site)
 191        cmafa = cma.get_form(request)
 192
 193        self.assertEqual(type(cmafa.base_fields['main_band'].widget.widget),
 194            Select)
 195        self.assertEqual(
 196            list(cmafa.base_fields['main_band'].widget.choices),
 197            [(u'', u'---------'), (self.band.id, u'The Doors')])
 198
 199        self.assertEqual(
 200            type(cmafa.base_fields['opening_band'].widget.widget), Select)
 201        self.assertEqual(
 202            list(cmafa.base_fields['opening_band'].widget.choices),
 203            [(u'', u'---------'), (self.band.id, u'The Doors')])
 204
 205        self.assertEqual(type(cmafa.base_fields['day'].widget), Select)
 206        self.assertEqual(list(cmafa.base_fields['day'].widget.choices),
 207            [('', '---------'), (1, 'Fri'), (2, 'Sat')])
 208
 209        self.assertEqual(type(cmafa.base_fields['transport'].widget),
 210            Select)
 211        self.assertEqual(
 212            list(cmafa.base_fields['transport'].widget.choices),
 213            [('', '---------'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')])
 214
 215    def test_foreign_key_as_radio_field(self):
 216        # Now specify all the fields as radio_fields.  Widgets should now be
 217        # RadioSelect, and the choices list should have a first entry of 'None' if
 218        # blank=True for the model field.  Finally, the widget should have the
 219        # 'radiolist' attr, and 'inline' as well if the field is specified HORIZONTAL.
 220
 221        class ConcertAdmin(ModelAdmin):
 222            radio_fields = {
 223                'main_band': HORIZONTAL,
 224                'opening_band': VERTICAL,
 225                'day': VERTICAL,
 226                'transport': HORIZONTAL,
 227            }
 228
 229        cma = ConcertAdmin(Concert, self.site)
 230        cmafa = cma.get_form(request)
 231
 232        self.assertEqual(type(cmafa.base_fields['main_band'].widget.widget),
 233            AdminRadioSelect)
 234        self.assertEqual(cmafa.base_fields['main_band'].widget.attrs,
 235            {'class': 'radiolist inline'})
 236        self.assertEqual(list(cmafa.base_fields['main_band'].widget.choices),
 237            [(self.band.id, u'The Doors')])
 238
 239        self.assertEqual(
 240            type(cmafa.base_fields['opening_band'].widget.widget),
 241            AdminRadioSelect)
 242        self.assertEqual(cmafa.base_fields['opening_band'].widget.attrs,
 243            {'class': 'radiolist'})
 244        self.assertEqual(
 245            list(cmafa.base_fields['opening_band'].widget.choices),
 246            [(u'', u'None'), (self.band.id, u'The Doors')])
 247
 248        self.assertEqual(type(cmafa.base_fields['day'].widget),
 249            AdminRadioSelect)
 250        self.assertEqual(cmafa.base_fields['day'].widget.attrs,
 251            {'class': 'radiolist'})
 252        self.assertEqual(list(cmafa.base_fields['day'].widget.choices),
 253            [(1, 'Fri'), (2, 'Sat')])
 254
 255        self.assertEqual(type(cmafa.base_fields['transport'].widget),
 256            AdminRadioSelect)
 257        self.assertEqual(cmafa.base_fields['transport'].widget.attrs,
 258            {'class': 'radiolist inline'})
 259        self.assertEqual(list(cmafa.base_fields['transport'].widget.choices),
 260            [('', u'None'), (1, 'Plane'), (2, 'Train'), (3, 'Bus')])
 261
 262        class AdminConcertForm(forms.ModelForm):
 263            class Meta:
 264                model = Concert
 265                exclude = ('transport',)
 266
 267        class ConcertAdmin(ModelAdmin):
 268            form = AdminConcertForm
 269
 270        ma = ConcertAdmin(Concert, self.site)
 271        self.assertEqual(ma.get_form(request).base_fields.keys(),
 272            ['main_band', 'opening_band', 'day'])
 273
 274        class AdminConcertForm(forms.ModelForm):
 275            extra = forms.CharField()
 276
 277            class Meta:
 278                model = Concert
 279                fields = ['extra', 'transport']
 280
 281        class ConcertAdmin(ModelAdmin):
 282            form = AdminConcertForm
 283
 284        ma = ConcertAdmin(Concert, self.site)
 285        self.assertEqual(ma.get_form(request).base_fields.keys(),
 286            ['extra', 'transport'])
 287
 288        class ConcertInline(TabularInline):
 289            form = AdminConcertForm
 290            model = Concert
 291            fk_name = 'main_band'
 292            can_delete = True
 293
 294        class BandAdmin(ModelAdmin):
 295            inlines = [
 296                ConcertInline
 297            ]
 298
 299        ma = BandAdmin(Band, self.site)
 300        self.assertEqual(
 301            list(ma.get_formsets(request))[0]().forms[0].fields.keys(),
 302            ['extra', 'transport', 'id', 'DELETE', 'main_band'])
 303
 304
 305class ValidationTests(unittest.TestCase):
 306    def test_validation_only_runs_in_debug(self):
 307        # Ensure validation only runs when DEBUG = True
 308        try:
 309            settings.DEBUG = True
 310
 311            class ValidationTestModelAdmin(ModelAdmin):
 312                raw_id_fields = 10
 313
 314            site = AdminSite()
 315
 316            self.assertRaisesRegexp(
 317                ImproperlyConfigured,
 318                "'ValidationTestModelAdmin.raw_id_fields' must be a list or tuple.",
 319                site.register,
 320                ValidationTestModel,
 321                ValidationTestModelAdmin,
 322            )
 323        finally:
 324            settings.DEBUG = False
 325
 326        site = AdminSite()
 327        site.register(ValidationTestModel, ValidationTestModelAdmin)
 328
 329    def test_raw_id_fields_validation(self):
 330
 331        class ValidationTestModelAdmin(ModelAdmin):
 332            raw_id_fields = 10
 333
 334        self.assertRaisesRegexp(
 335            ImproperlyConfigured,
 336            "'ValidationTestModelAdmin.raw_id_fields' must be a list or tuple.",
 337            validate,
 338            ValidationTestModelAdmin,
 339            ValidationTestModel,
 340        )
 341
 342        class ValidationTestModelAdmin(ModelAdmin):
 343            raw_id_fields = ('non_existent_field',)
 344
 345        self.assertRaisesRegexp(
 346            ImproperlyConfigured,
 347            "'ValidationTestModelAdmin.raw_id_fields' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 348            validate,
 349            ValidationTestModelAdmin,
 350            ValidationTestModel,
 351        )
 352
 353        class ValidationTestModelAdmin(ModelAdmin):
 354            raw_id_fields = ('name',)
 355
 356        self.assertRaisesRegexp(
 357            ImproperlyConfigured,
 358            "'ValidationTestModelAdmin.raw_id_fields\[0\]', 'name' must be either a ForeignKey or ManyToManyField.",
 359            validate,
 360            ValidationTestModelAdmin,
 361            ValidationTestModel,
 362        )
 363
 364        class ValidationTestModelAdmin(ModelAdmin):
 365            raw_id_fields = ('users',)
 366
 367        validate(ValidationTestModelAdmin, ValidationTestModel)
 368
 369    def test_fieldsets_validation(self):
 370
 371        class ValidationTestModelAdmin(ModelAdmin):
 372            fieldsets = 10
 373
 374        self.assertRaisesRegexp(
 375            ImproperlyConfigured,
 376            "'ValidationTestModelAdmin.fieldsets' must be a list or tuple.",
 377            validate,
 378            ValidationTestModelAdmin,
 379            ValidationTestModel,
 380        )
 381
 382        class ValidationTestModelAdmin(ModelAdmin):
 383            fieldsets = ({},)
 384
 385        self.assertRaisesRegexp(
 386            ImproperlyConfigured,
 387            "'ValidationTestModelAdmin.fieldsets\[0\]' must be a list or tuple.",
 388            validate,
 389            ValidationTestModelAdmin,
 390            ValidationTestModel,
 391        )
 392
 393        class ValidationTestModelAdmin(ModelAdmin):
 394            fieldsets = ((),)
 395
 396        self.assertRaisesRegexp(
 397            ImproperlyConfigured,
 398            "'ValidationTestModelAdmin.fieldsets\[0\]' does not have exactly two elements.",
 399            validate,
 400            ValidationTestModelAdmin,
 401            ValidationTestModel,
 402        )
 403
 404        class ValidationTestModelAdmin(ModelAdmin):
 405            fieldsets = (("General", ()),)
 406
 407        self.assertRaisesRegexp(
 408            ImproperlyConfigured,
 409            "'ValidationTestModelAdmin.fieldsets\[0\]\[1\]' must be a dictionary.",
 410            validate,
 411            ValidationTestModelAdmin,
 412            ValidationTestModel,
 413        )
 414
 415        class ValidationTestModelAdmin(ModelAdmin):
 416            fieldsets = (("General", {}),)
 417
 418        self.assertRaisesRegexp(
 419            ImproperlyConfigured,
 420            "'fields' key is required in ValidationTestModelAdmin.fieldsets\[0\]\[1\] field options dict.",
 421            validate,
 422            ValidationTestModelAdmin,
 423            ValidationTestModel,
 424        )
 425
 426        class ValidationTestModelAdmin(ModelAdmin):
 427            fieldsets = (("General", {"fields": ("non_existent_field",)}),)
 428
 429        self.assertRaisesRegexp(
 430            ImproperlyConfigured,
 431            "'ValidationTestModelAdmin.fieldsets\[0\]\[1\]\['fields'\]' refers to field 'non_existent_field' that is missing from the form.",
 432            validate,
 433            ValidationTestModelAdmin,
 434            ValidationTestModel,
 435        )
 436
 437        class ValidationTestModelAdmin(ModelAdmin):
 438            fieldsets = (("General", {"fields": ("name",)}),)
 439
 440        validate(ValidationTestModelAdmin, ValidationTestModel)
 441
 442        class ValidationTestModelAdmin(ModelAdmin):
 443            fieldsets = (("General", {"fields": ("name",)}),)
 444            fields = ["name",]
 445
 446        self.assertRaisesRegexp(
 447            ImproperlyConfigured,
 448            "Both fieldsets and fields are specified in ValidationTestModelAdmin.",
 449            validate,
 450            ValidationTestModelAdmin,
 451            ValidationTestModel,
 452        )
 453
 454        class ValidationTestModelAdmin(ModelAdmin):
 455            fieldsets = [(None, {'fields': ['name', 'name']})]
 456
 457        self.assertRaisesRegexp(
 458            ImproperlyConfigured,
 459            "There are duplicate field\(s\) in ValidationTestModelAdmin.fieldsets",
 460            validate,
 461            ValidationTestModelAdmin,
 462            ValidationTestModel,
 463        )
 464
 465        class ValidationTestModelAdmin(ModelAdmin):
 466            fields = ["name", "name"]
 467
 468        self.assertRaisesRegexp(
 469            ImproperlyConfigured,
 470            "There are duplicate field\(s\) in ValidationTestModelAdmin.fields",
 471            validate,
 472            ValidationTestModelAdmin,
 473            ValidationTestModel,
 474        )
 475
 476    def test_form_validation(self):
 477
 478        class FakeForm(object):
 479            pass
 480
 481        class ValidationTestModelAdmin(ModelAdmin):
 482            form = FakeForm
 483
 484        self.assertRaisesRegexp(
 485            ImproperlyConfigured,
 486            "ValidationTestModelAdmin.form does not inherit from BaseModelForm.",
 487            validate,
 488            ValidationTestModelAdmin,
 489            ValidationTestModel,
 490        )
 491
 492    def test_fieldsets_with_custom_form_validation(self):
 493
 494        class BandAdmin(ModelAdmin):
 495
 496            fieldsets = (
 497                ('Band', {
 498                    'fields': ('non_existent_field',)
 499                }),
 500            )
 501
 502        self.assertRaisesRegexp(
 503            ImproperlyConfigured,
 504            "'BandAdmin.fieldsets\[0\]\[1\]\['fields'\]' refers to field 'non_existent_field' that is missing from the form.",
 505            validate,
 506            BandAdmin,
 507            Band,
 508        )
 509
 510        class BandAdmin(ModelAdmin):
 511            fieldsets = (
 512                ('Band', {
 513                    'fields': ('name',)
 514                }),
 515            )
 516
 517        validate(BandAdmin, Band)
 518
 519        class AdminBandForm(forms.ModelForm):
 520            class Meta:
 521                model = Band
 522
 523        class BandAdmin(ModelAdmin):
 524            form = AdminBandForm
 525
 526            fieldsets = (
 527                ('Band', {
 528                    'fields': ('non_existent_field',)
 529                }),
 530            )
 531
 532        self.assertRaisesRegexp(
 533            ImproperlyConfigured,
 534            "'BandAdmin.fieldsets\[0]\[1\]\['fields'\]' refers to field 'non_existent_field' that is missing from the form.",
 535            validate,
 536            BandAdmin,
 537            Band,
 538        )
 539
 540        class AdminBandForm(forms.ModelForm):
 541            delete = forms.BooleanField()
 542
 543            class Meta:
 544                model = Band
 545
 546        class BandAdmin(ModelAdmin):
 547            form = AdminBandForm
 548
 549            fieldsets = (
 550                ('Band', {
 551                    'fields': ('name', 'bio', 'sign_date', 'delete')
 552                }),
 553            )
 554
 555        validate(BandAdmin, Band)
 556
 557    def test_filter_vertical_validation(self):
 558
 559        class ValidationTestModelAdmin(ModelAdmin):
 560            filter_vertical = 10
 561
 562        self.assertRaisesRegexp(
 563            ImproperlyConfigured,
 564            "'ValidationTestModelAdmin.filter_vertical' must be a list or tuple.",
 565            validate,
 566            ValidationTestModelAdmin,
 567            ValidationTestModel,
 568        )
 569
 570        class ValidationTestModelAdmin(ModelAdmin):
 571            filter_vertical = ("non_existent_field",)
 572
 573        self.assertRaisesRegexp(
 574            ImproperlyConfigured,
 575            "'ValidationTestModelAdmin.filter_vertical' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 576            validate,
 577            ValidationTestModelAdmin,
 578            ValidationTestModel,
 579        )
 580
 581        class ValidationTestModelAdmin(ModelAdmin):
 582            filter_vertical = ("name",)
 583
 584        self.assertRaisesRegexp(
 585            ImproperlyConfigured,
 586            "'ValidationTestModelAdmin.filter_vertical\[0\]' must be a ManyToManyField.",
 587            validate,
 588            ValidationTestModelAdmin,
 589            ValidationTestModel,
 590        )
 591
 592        class ValidationTestModelAdmin(ModelAdmin):
 593            filter_vertical = ("users",)
 594
 595        validate(ValidationTestModelAdmin, ValidationTestModel)
 596
 597    def test_filter_horizontal_validation(self):
 598
 599        class ValidationTestModelAdmin(ModelAdmin):
 600            filter_horizontal = 10
 601
 602        self.assertRaisesRegexp(
 603            ImproperlyConfigured,
 604            "'ValidationTestModelAdmin.filter_horizontal' must be a list or tuple.",
 605            validate,
 606            ValidationTestModelAdmin,
 607            ValidationTestModel,
 608        )
 609
 610        class ValidationTestModelAdmin(ModelAdmin):
 611            filter_horizontal = ("non_existent_field",)
 612
 613        self.assertRaisesRegexp(
 614            ImproperlyConfigured,
 615            "'ValidationTestModelAdmin.filter_horizontal' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 616            validate,
 617            ValidationTestModelAdmin,
 618            ValidationTestModel,
 619        )
 620
 621        class ValidationTestModelAdmin(ModelAdmin):
 622            filter_horizontal = ("name",)
 623
 624        self.assertRaisesRegexp(
 625            ImproperlyConfigured,
 626            "'ValidationTestModelAdmin.filter_horizontal\[0\]' must be a ManyToManyField.",
 627            validate,
 628            ValidationTestModelAdmin,
 629            ValidationTestModel,
 630        )
 631
 632        class ValidationTestModelAdmin(ModelAdmin):
 633            filter_horizontal = ("users",)
 634
 635        validate(ValidationTestModelAdmin, ValidationTestModel)
 636
 637    def test_radio_fields_validation(self):
 638
 639        class ValidationTestModelAdmin(ModelAdmin):
 640            radio_fields = ()
 641
 642        self.assertRaisesRegexp(
 643            ImproperlyConfigured,
 644            "'ValidationTestModelAdmin.radio_fields' must be a dictionary.",
 645            validate,
 646            ValidationTestModelAdmin,
 647            ValidationTestModel,
 648        )
 649
 650        class ValidationTestModelAdmin(ModelAdmin):
 651            radio_fields = {"non_existent_field": None}
 652
 653        self.assertRaisesRegexp(
 654            ImproperlyConfigured,
 655            "'ValidationTestModelAdmin.radio_fields' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 656            validate,
 657            ValidationTestModelAdmin,
 658            ValidationTestModel,
 659        )
 660
 661        class ValidationTestModelAdmin(ModelAdmin):
 662            radio_fields = {"name": None}
 663
 664        self.assertRaisesRegexp(
 665            ImproperlyConfigured,
 666            "'ValidationTestModelAdmin.radio_fields\['name'\]' is neither an instance of ForeignKey nor does have choices set.",
 667            validate,
 668            ValidationTestModelAdmin,
 669            ValidationTestModel,
 670        )
 671
 672        class ValidationTestModelAdmin(ModelAdmin):
 673            radio_fields = {"state": None}
 674
 675        self.assertRaisesRegexp(
 676            ImproperlyConfigured,
 677            "'ValidationTestModelAdmin.radio_fields\['state'\]' is neither admin.HORIZONTAL nor admin.VERTICAL.",
 678            validate,
 679            ValidationTestModelAdmin,
 680            ValidationTestModel,
 681        )
 682
 683        class ValidationTestModelAdmin(ModelAdmin):
 684            radio_fields = {"state": VERTICAL}
 685
 686        validate(ValidationTestModelAdmin, ValidationTestModel)
 687
 688    def test_prepopulated_fields_validation(self):
 689
 690        class ValidationTestModelAdmin(ModelAdmin):
 691            prepopulated_fields = ()
 692
 693        self.assertRaisesRegexp(
 694            ImproperlyConfigured,
 695            "'ValidationTestModelAdmin.prepopulated_fields' must be a dictionary.",
 696            validate,
 697            ValidationTestModelAdmin,
 698            ValidationTestModel,
 699        )
 700
 701        class ValidationTestModelAdmin(ModelAdmin):
 702            prepopulated_fields = {"non_existent_field": None}
 703
 704        self.assertRaisesRegexp(
 705            ImproperlyConfigured,
 706            "'ValidationTestModelAdmin.prepopulated_fields' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 707            validate,
 708            ValidationTestModelAdmin,
 709            ValidationTestModel,
 710        )
 711
 712        class ValidationTestModelAdmin(ModelAdmin):
 713            prepopulated_fields = {"slug": ("non_existent_field",)}
 714
 715        self.assertRaisesRegexp(
 716            ImproperlyConfigured,
 717            "'ValidationTestModelAdmin.prepopulated_fields\['slug'\]\[0\]' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 718            validate,
 719            ValidationTestModelAdmin,
 720            ValidationTestModel,
 721        )
 722
 723        class ValidationTestModelAdmin(ModelAdmin):
 724            prepopulated_fields = {"users": ("name",)}
 725
 726        self.assertRaisesRegexp(
 727            ImproperlyConfigured,
 728            "'ValidationTestModelAdmin.prepopulated_fields\['users'\]' is either a DateTimeField, ForeignKey or ManyToManyField. This isn't allowed.",
 729            validate,
 730            ValidationTestModelAdmin,
 731            ValidationTestModel,
 732        )
 733
 734        class ValidationTestModelAdmin(ModelAdmin):
 735            prepopulated_fields = {"slug": ("name",)}
 736
 737        validate(ValidationTestModelAdmin, ValidationTestModel)
 738
 739    def test_list_display_validation(self):
 740
 741        class ValidationTestModelAdmin(ModelAdmin):
 742            list_display = 10
 743
 744        self.assertRaisesRegexp(
 745            ImproperlyConfigured,
 746            "'ValidationTestModelAdmin.list_display' must be a list or tuple.",
 747            validate,
 748            ValidationTestModelAdmin,
 749            ValidationTestModel,
 750        )
 751
 752        class ValidationTestModelAdmin(ModelAdmin):
 753            list_display = ('non_existent_field',)
 754
 755        self.assertRaisesRegexp(
 756            ImproperlyConfigured,
 757            "ValidationTestModelAdmin.list_display\[0\], 'non_existent_field' is not a callable or an attribute of 'ValidationTestModelAdmin' or found in the model 'ValidationTestModel'.",
 758            validate,
 759            ValidationTestModelAdmin,
 760            ValidationTestModel,
 761        )
 762
 763        class ValidationTestModelAdmin(ModelAdmin):
 764            list_display = ('users',)
 765
 766        self.assertRaisesRegexp(
 767            ImproperlyConfigured,
 768            "'ValidationTestModelAdmin.list_display\[0\]', 'users' is a ManyToManyField which is not supported.",
 769            validate,
 770            ValidationTestModelAdmin,
 771            ValidationTestModel,
 772        )
 773
 774        def a_callable(obj):
 775            pass
 776
 777        class ValidationTestModelAdmin(ModelAdmin):
 778            def a_method(self, obj):
 779                pass
 780            list_display = ('name', 'decade_published_in', 'a_method', a_callable)
 781
 782        validate(ValidationTestModelAdmin, ValidationTestModel)
 783
 784    def test_list_display_links_validation(self):
 785
 786        class ValidationTestModelAdmin(ModelAdmin):
 787            list_display_links = 10
 788
 789        self.assertRaisesRegexp(
 790            ImproperlyConfigured,
 791            "'ValidationTestModelAdmin.list_display_links' must be a list or tuple.",
 792            validate,
 793            ValidationTestModelAdmin,
 794            ValidationTestModel,
 795        )
 796
 797        class ValidationTestModelAdmin(ModelAdmin):
 798            list_display_links = ('non_existent_field',)
 799
 800        self.assertRaisesRegexp(
 801            ImproperlyConfigured,
 802            "'ValidationTestModelAdmin.list_display_links\[0\]' refers to 'non_existent_field' which is not defined in 'list_display'.",
 803            validate,
 804            ValidationTestModelAdmin,
 805            ValidationTestModel,
 806        )
 807
 808        class ValidationTestModelAdmin(ModelAdmin):
 809            list_display_links = ('name',)
 810
 811        self.assertRaisesRegexp(
 812            ImproperlyConfigured,
 813            "'ValidationTestModelAdmin.list_display_links\[0\]' refers to 'name' which is not defined in 'list_display'.",
 814            validate,
 815            ValidationTestModelAdmin,
 816            ValidationTestModel,
 817        )
 818
 819        def a_callable(obj):
 820            pass
 821
 822        class ValidationTestModelAdmin(ModelAdmin):
 823            def a_method(self, obj):
 824                pass
 825            list_display = ('name', 'decade_published_in', 'a_method', a_callable)
 826            list_display_links = ('name', 'decade_published_in', 'a_method', a_callable)
 827
 828        validate(ValidationTestModelAdmin, ValidationTestModel)
 829
 830    def test_list_filter_validation(self):
 831
 832        class ValidationTestModelAdmin(ModelAdmin):
 833            list_filter = 10
 834
 835        self.assertRaisesRegexp(
 836            ImproperlyConfigured,
 837            "'ValidationTestModelAdmin.list_filter' must be a list or tuple.",
 838            validate,
 839            ValidationTestModelAdmin,
 840            ValidationTestModel,
 841        )
 842
 843        class ValidationTestModelAdmin(ModelAdmin):
 844            list_filter = ('non_existent_field',)
 845
 846        self.assertRaisesRegexp(
 847            ImproperlyConfigured,
 848            "'ValidationTestModelAdmin.list_filter\[0\]' refers to 'non_existent_field' which does not refer to a Field.",
 849            validate,
 850            ValidationTestModelAdmin,
 851            ValidationTestModel,
 852        )
 853
 854        class ValidationTestModelAdmin(ModelAdmin):
 855            list_filter = ('is_active',)
 856
 857        validate(ValidationTestModelAdmin, ValidationTestModel)
 858
 859    def test_list_per_page_validation(self):
 860
 861        class ValidationTestModelAdmin(ModelAdmin):
 862            list_per_page = 'hello'
 863
 864        self.assertRaisesRegexp(
 865            ImproperlyConfigured,
 866            "'ValidationTestModelAdmin.list_per_page' should be a integer.",
 867            validate,
 868            ValidationTestModelAdmin,
 869            ValidationTestModel,
 870        )
 871
 872        class ValidationTestModelAdmin(ModelAdmin):
 873            list_per_page = 100
 874
 875        validate(ValidationTestModelAdmin, ValidationTestModel)
 876
 877    def test_search_fields_validation(self):
 878
 879        class ValidationTestModelAdmin(ModelAdmin):
 880            search_fields = 10
 881
 882        self.assertRaisesRegexp(
 883            ImproperlyConfigured,
 884            "'ValidationTestModelAdmin.search_fields' must be a list or tuple.",
 885            validate,
 886            ValidationTestModelAdmin,
 887            ValidationTestModel,
 888        )
 889
 890    def test_date_hierarchy_validation(self):
 891
 892        class ValidationTestModelAdmin(ModelAdmin):
 893            date_hierarchy = 'non_existent_field'
 894
 895        self.assertRaisesRegexp(
 896            ImproperlyConfigured,
 897            "'ValidationTestModelAdmin.date_hierarchy' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 898            validate,
 899            ValidationTestModelAdmin,
 900            ValidationTestModel,
 901        )
 902
 903        class ValidationTestModelAdmin(ModelAdmin):
 904            date_hierarchy = 'name'
 905
 906        self.assertRaisesRegexp(
 907            ImproperlyConfigured,
 908            "'ValidationTestModelAdmin.date_hierarchy is neither an instance of DateField nor DateTimeField.",
 909            validate,
 910            ValidationTestModelAdmin,
 911            ValidationTestModel,
 912        )
 913
 914        class ValidationTestModelAdmin(ModelAdmin):
 915            date_hierarchy = 'pub_date'
 916
 917        validate(ValidationTestModelAdmin, ValidationTestModel)
 918
 919    def test_ordering_validation(self):
 920
 921        class ValidationTestModelAdmin(ModelAdmin):
 922            ordering = 10
 923
 924        self.assertRaisesRegexp(
 925            ImproperlyConfigured,
 926            "'ValidationTestModelAdmin.ordering' must be a list or tuple.",
 927            validate,
 928            ValidationTestModelAdmin,
 929            ValidationTestModel,
 930        )
 931
 932        class ValidationTestModelAdmin(ModelAdmin):
 933            ordering = ('non_existent_field',)
 934
 935        self.assertRaisesRegexp(
 936            ImproperlyConfigured,
 937            "'ValidationTestModelAdmin.ordering\[0\]' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.",
 938            validate,
 939            ValidationTestModelAdmin,
 940            ValidationTestModel,
 941        )
 942
 943        class ValidationTestModelAdmin(ModelAdmin):
 944            ordering = ('?', 'name')
 945
 946        self.assertRaisesRegexp(
 947            ImproperlyConfigured,
 948            "'ValidationTestModelAdmin.ordering' has the random ordering marker '\?', but contains other fields as well. Please either remove '\?' or the other fields.",
 949            validate,
 950            ValidationTestModelAdmin,
 951            ValidationTestModel,
 952        )
 953
 954        class ValidationTestModelAdmin(ModelAdmin):
 955            ordering = ('?',)
 956
 957        validate(ValidationTestModelAdmin, ValidationTestModel)
 958
 959        class ValidationTestModelAdmin(ModelAdmin):
 960            ordering = ('band__name',)
 961
 962        validate(ValidationTestModelAdmin, ValidationTestModel)
 963
 964        class ValidationTestModelAdmin(ModelAdmin):
 965            ordering = ('name',)
 966
 967        validate(ValidationTestModelAdmin, ValidationTestModel)
 968
 969    def test_list_select_related_validation(self):
 970
 971        class ValidationTestModelAdmin(ModelAdmin):
 972            list_select_related = 1
 973
 974        self.assertRaisesRegexp(
 975            ImproperlyConfigured,
 976            "'ValidationTestModelAdmin.list_select_related' should be a boolean.",
 977            validate,
 978            ValidationTestModelAdmin,
 979            ValidationTestModel,
 980        )
 981
 982        class ValidationTestModelAdmin(ModelAdmin):
 983            list_select_related = False
 984
 985        validate(ValidationTestModelAdmin, ValidationTestModel)
 986
 987    def test_save_as_validation(self):
 988
 989        class ValidationTestModelAdmin(ModelAdmin):
 990            save_as = 1
 991
 992        self.assertRaisesRegexp(
 993            ImproperlyConfigured,
 994            "'ValidationTestModelAdmin.save_as' should be a boolean.",
 995            validate,
 996            ValidationTestModelAdmin,
 997            ValidationTestModel,
 998        )
 999
1000        class ValidationTestModelAdmin(ModelAdmin):
1001            save_as = True
1002
1003        validate(ValidationTestModelAdmin, ValidationTestModel)
1004
1005    def test_save_on_top_validation(self):
1006
1007        class ValidationTestModelAdmin(ModelAdmin):
1008            save_on_top = 1
1009
1010        self.assertRaisesRegexp(
1011            ImproperlyConfigured,
1012            "'ValidationTestModelAdmin.save_on_top' should be a boolean.",
1013            validate,
1014            ValidationTestModelAdmin,
1015            ValidationTestModel,
1016        )
1017
1018        class ValidationTestModelAdmin(ModelAdmin):
1019            save_on_top = True
1020
1021        validate(ValidationTestModelAdmin, ValidationTestModel)
1022
1023    def test_inlines_validation(self):
1024
1025        class ValidationTestModelAdmin(ModelAdmin):
1026            inlines = 10
1027
1028        self.assertRaisesRegexp(
1029            ImproperlyConfigured,
1030            "'ValidationTestModelAdmin.inlines' must be a list or tuple.",
1031            validate,
1032            ValidationTestModelAdmin,
1033            ValidationTestModel,
1034        )
1035
1036        class ValidationTestInline(object):
1037            pass
1038
1039        class ValidationTestModelAdmin(ModelAdmin):
1040            inlines = [ValidationTestInline]
1041
1042        self.assertRaisesRegexp(
1043            ImproperlyConfigured,
1044            "'ValidationTestModelAdmin.inlines\[0\]' does not inherit from BaseModelAdmin.",
1045            validate,
1046            ValidationTestModelAdmin,
1047            ValidationTestModel,
1048        )
1049
1050        class ValidationTestInline(TabularInline):
1051            pass
1052
1053        class ValidationTestModelAdmin(ModelAdmin):
1054            inlines = [ValidationTestInline]
1055
1056        self.assertRaisesRegexp(
1057            ImproperlyConfigured,
1058            "'model' is a required attribute of 'ValidationTestModelAdmin.inlines\[0\]'.",
1059            validate,
1060            ValidationTestModelAdmin,
1061            ValidationTestModel,
1062        )
1063
1064        class SomethingBad(object):
1065            pass
1066
1067        class ValidationTestInline(TabularInline):
1068            model = SomethingBad
1069
1070        class ValidationTestModelAdmin(ModelAdmin):
1071            inlines = [ValidationTestInline]
1072
1073        self.assertRaisesRegexp(
1074            ImproperlyConfigured,
1075            "'ValidationTestModelAdmin.inlines\[0\].model' does not inherit from models.Model.",
1076            validate,
1077            ValidationTestModelAdmin,
1078            ValidationTestModel,
1079        )
1080
1081        class ValidationTestInline(TabularInline):
1082            model = ValidationTestInlineModel
1083
1084        class ValidationTestModelAdmin(ModelAdmin):
1085            inlines = [ValidationTestInline]
1086
1087        validate(ValidationTestModelAdmin, ValidationTestModel)
1088
1089    def test_fields_validation(self):
1090
1091        class ValidationTestInline(TabularInline):
1092            model = ValidationTestInlineModel
1093            fields = 10
1094
1095        class ValidationTestModelAdmin(ModelAdmin):
1096            inlines = [ValidationTestInline]
1097
1098        self.assertRaisesRegexp(
1099            ImproperlyConfigured,
1100            "'ValidationTestInline.fields' must be a list or tuple.",
1101            validate,
1102            ValidationTestModelAdmin,
1103            ValidationTestModel,
1104        )
1105
1106        class ValidationTestInline(TabularInline):
1107            model = ValidationTestInlineModel
1108            fields = ("non_existent_field",)
1109
1110        class ValidationTestModelAdmin(ModelAdmin):
1111            inlines = [ValidationTestInline]
1112
1113        self.assertRaisesRegexp(
1114            ImproperlyConfigured,
1115            "'ValidationTestInline.fields' refers to field 'non_existent_field' that is missing from the form.",
1116            validate,
1117            ValidationTestModelAdmin,
1118            ValidationTestModel,
1119        )
1120
1121    def test_fk_name_validation(self):
1122
1123        class ValidationTestInline(TabularInline):
1124            model = ValidationTestInlineModel
1125            fk_name = "non_existent_field"
1126
1127        class ValidationTestModelAdmin(ModelAdmin):
1128            inlines = [ValidationTestInline]
1129
1130        self.assertRaisesRegexp(
1131            ImproperlyConfigured,
1132            "'ValidationTestInline.fk_name' refers to field 'non_existent_field' that is missing from model 'ValidationTestInlineModel'.",
1133            validate,
1134            ValidationTestModelAdmin,
1135            ValidationTestModel,
1136        )
1137
1138        class ValidationTestInline(TabularInline):
1139            model = ValidationTestInlineModel
1140            fk_name = "parent"
1141
1142        class ValidationTestModelAdmin(ModelAdmin):
1143            inlines = [ValidationTestInline]
1144
1145        validate(ValidationTestModelAdmin, ValidationTestModel)
1146
1147    def test_extra_validation(self):
1148
1149        class ValidationTestInline(TabularInline):
1150            model = ValidationTestInlineModel
1151            extra = "hello"
1152
1153        class ValidationTestModelAdmin(ModelAdmin):
1154            inlines = [ValidationTestInline]
1155
1156        self.assertRaisesRegexp(
1157            ImproperlyConfigured,
1158            "'ValidationTestInline.extra' should be a integer.",
1159            validate,
1160            ValidationTestModelAdmin,
1161            ValidationTestModel,
1162        )
1163
1164        class ValidationTestInline(TabularInline):
1165            model = ValidationTestInlineModel
1166            extra = 2
1167
1168        class ValidationTestModelAdmin(ModelAdmin):
1169            inlines = [ValidationTestInline]
1170
1171        validate(ValidationTestModelAdmin, ValidationTestModel)
1172
1173    def test_max_num_validation(self):
1174
1175        class ValidationTestInline(TabularInline):
1176            model = ValidationTestInlineModel
1177            max_num = "hello"
1178
1179        class ValidationTestModelAdmin(ModelAdmin):
1180            inlines = [ValidationTestInline]
1181
1182        self.assertRaisesRegexp(
1183            ImproperlyConfigured,
1184            "'ValidationTestInline.max_num' should be an integer or None \(default\).",
1185            validate,
1186            ValidationTestModelAdmin,
1187            ValidationTestModel,
1188        )
1189
1190        class ValidationTestInline(TabularInline):
1191            model = ValidationTestInlineModel
1192            max_num = 2
1193
1194        class ValidationTestModelAdmin(ModelAdmin):
1195            inlines = [ValidationTestInline]
1196
1197        validate(ValidationTestModelAdmin, ValidationTestModel)
1198
1199    def test_formset_validation(self):
1200
1201        class FakeFormSet(object):
1202            pass
1203
1204        class ValidationTestInline(TabularInline):
1205            model = ValidationTestInlineModel
1206            formset = FakeFormSet
1207
1208        class ValidationTestModelAdmin(ModelAdmin):
1209            inlines = [ValidationTestInline]
1210
1211        self.assertRaisesRegexp(
1212            ImproperlyConfigured,
1213            "'ValidationTestInline.formset' does not inherit from BaseModelFormSet.",
1214            validate,
1215            ValidationTestModelAdmin,
1216            ValidationTestModel,
1217        )
1218
1219        class RealModelFormSet(BaseModelFormSet):
1220            pass
1221
1222        class ValidationTestInline(TabularInline):
1223            model = ValidationTestInlineModel
1224            formset = RealModelFormSet
1225
1226        class ValidationTestModelAdmin(ModelAdmin):
1227            inlines = [ValidationTestInline]
1228
1229        validate(ValidationTestModelAdmin, ValidationTestModel)