/tests/regressiontests/modeladmin/tests.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)