mirror of
				https://github.com/django/django.git
				synced 2025-10-29 08:36:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1135 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1135 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import unicode_literals
 | |
| 
 | |
| from django import forms
 | |
| from django.contrib.admin import BooleanFieldListFilter, SimpleListFilter
 | |
| from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline
 | |
| from django.contrib.admin.sites import AdminSite
 | |
| from django.core.checks import Error
 | |
| from django.forms.models import BaseModelFormSet
 | |
| from django.test import SimpleTestCase
 | |
| 
 | |
| from .models import Band, ValidationTestInlineModel, ValidationTestModel
 | |
| 
 | |
| 
 | |
| class CheckTestCase(SimpleTestCase):
 | |
| 
 | |
|     def assertIsInvalid(self, model_admin, model, msg, id=None, hint=None, invalid_obj=None):
 | |
|         invalid_obj = invalid_obj or model_admin
 | |
|         admin_obj = model_admin(model, AdminSite())
 | |
|         self.assertEqual(admin_obj.check(), [Error(msg, hint=hint, obj=invalid_obj, id=id)])
 | |
| 
 | |
|     def assertIsInvalidRegexp(self, model_admin, model, msg, id=None, hint=None, invalid_obj=None):
 | |
|         """
 | |
|         Same as assertIsInvalid but treats the given msg as a regexp.
 | |
|         """
 | |
|         invalid_obj = invalid_obj or model_admin
 | |
|         admin_obj = model_admin(model, AdminSite())
 | |
|         errors = admin_obj.check()
 | |
|         self.assertEqual(len(errors), 1)
 | |
|         error = errors[0]
 | |
|         self.assertEqual(error.hint, hint)
 | |
|         self.assertEqual(error.obj, invalid_obj)
 | |
|         self.assertEqual(error.id, id)
 | |
|         self.assertRegex(error.msg, msg)
 | |
| 
 | |
|     def assertIsValid(self, model_admin, model):
 | |
|         admin_obj = model_admin(model, AdminSite())
 | |
|         self.assertEqual(admin_obj.check(), [])
 | |
| 
 | |
| 
 | |
| class RawIdCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             raw_id_fields = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'raw_id_fields' must be a list or tuple.",
 | |
|             'admin.E001'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             raw_id_fields = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'raw_id_fields[0]' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E002'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             raw_id_fields = ('name',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'raw_id_fields[0]' must be a foreign key or a "
 | |
|             "many-to-many field.",
 | |
|             'admin.E003'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             raw_id_fields = ('users',)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class FieldsetsCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = (('General', {'fields': ('name',)}),)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fieldsets' must be a list or tuple.",
 | |
|             'admin.E007'
 | |
|         )
 | |
| 
 | |
|     def test_non_iterable_item(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = ({},)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fieldsets[0]' must be a list or tuple.",
 | |
|             'admin.E008'
 | |
|         )
 | |
| 
 | |
|     def test_item_not_a_pair(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = ((),)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fieldsets[0]' must be of length 2.",
 | |
|             'admin.E009'
 | |
|         )
 | |
| 
 | |
|     def test_second_element_of_item_not_a_dict(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = (('General', ()),)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fieldsets[0][1]' must be a dictionary.",
 | |
|             'admin.E010'
 | |
|         )
 | |
| 
 | |
|     def test_missing_fields_key(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = (('General', {}),)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fieldsets[0][1]' must contain the key 'fields'.",
 | |
|             'admin.E011'
 | |
|         )
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = (('General', {'fields': ('name',)}),)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_specified_both_fields_and_fieldsets(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = (('General', {'fields': ('name',)}),)
 | |
|             fields = ['name']
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "Both 'fieldsets' and 'fields' are specified.",
 | |
|             'admin.E005'
 | |
|         )
 | |
| 
 | |
|     def test_duplicate_fields(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fieldsets = [(None, {'fields': ['name', 'name']})]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "There are duplicate field(s) in 'fieldsets[0][1]'.",
 | |
|             'admin.E012'
 | |
|         )
 | |
| 
 | |
|     def test_fieldsets_with_custom_form_validation(self):
 | |
|         class BandAdmin(ModelAdmin):
 | |
|             fieldsets = (('Band', {'fields': ('name',)}),)
 | |
| 
 | |
|         self.assertIsValid(BandAdmin, Band)
 | |
| 
 | |
| 
 | |
| class FieldsCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_duplicate_fields_in_fields(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             fields = ['name', 'name']
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fields' contains duplicate field(s).",
 | |
|             'admin.E006'
 | |
|         )
 | |
| 
 | |
|     def test_inline(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             fields = 10
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'fields' must be a list or tuple.",
 | |
|             'admin.E004',
 | |
|             invalid_obj=ValidationTestInline
 | |
|         )
 | |
| 
 | |
| 
 | |
| class FormCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_invalid_type(self):
 | |
|         class FakeForm(object):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             form = FakeForm
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'form' must inherit from 'BaseModelForm'.",
 | |
|             'admin.E016'
 | |
|         )
 | |
| 
 | |
|     def test_fieldsets_with_custom_form_validation(self):
 | |
| 
 | |
|         class BandAdmin(ModelAdmin):
 | |
|             fieldsets = (('Band', {'fields': ('name',)}),)
 | |
| 
 | |
|         self.assertIsValid(BandAdmin, Band)
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class AdminBandForm(forms.ModelForm):
 | |
|             delete = forms.BooleanField()
 | |
| 
 | |
|         class BandAdmin(ModelAdmin):
 | |
|             form = AdminBandForm
 | |
|             fieldsets = (
 | |
|                 ('Band', {
 | |
|                     'fields': ('name', 'bio', 'sign_date', 'delete')
 | |
|                 }),
 | |
|             )
 | |
| 
 | |
|         self.assertIsValid(BandAdmin, Band)
 | |
| 
 | |
| 
 | |
| class FilterVerticalCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_vertical = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'filter_vertical' must be a list or tuple.",
 | |
|             'admin.E017'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_vertical = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'filter_vertical[0]' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E019'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_vertical = ('name',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'filter_vertical[0]' must be a many-to-many field.",
 | |
|             'admin.E020'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_vertical = ('users',)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class FilterHorizontalCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_horizontal = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'filter_horizontal' must be a list or tuple.",
 | |
|             'admin.E018'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_horizontal = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'filter_horizontal[0]' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E019'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_horizontal = ('name',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'filter_horizontal[0]' must be a many-to-many field.",
 | |
|             'admin.E020'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             filter_horizontal = ('users',)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class RadioFieldsCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_dictionary(self):
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             radio_fields = ()
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'radio_fields' must be a dictionary.",
 | |
|             'admin.E021'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             radio_fields = {'non_existent_field': VERTICAL}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'radio_fields' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E022'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             radio_fields = {'name': VERTICAL}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'radio_fields' refers to 'name', which is not an instance "
 | |
|             "of ForeignKey, and does not have a 'choices' definition.",
 | |
|             'admin.E023'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_value(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             radio_fields = {'state': None}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'radio_fields[\"state\"]' must be either admin.HORIZONTAL or admin.VERTICAL.",
 | |
|             'admin.E024'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             radio_fields = {'state': VERTICAL}
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class PrepopulatedFieldsCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_dictionary(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             prepopulated_fields = ()
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'prepopulated_fields' must be a dictionary.",
 | |
|             'admin.E026'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             prepopulated_fields = {'non_existent_field': ('slug',)}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'prepopulated_fields' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E027'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field_again(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             prepopulated_fields = {'slug': ('non_existent_field',)}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'prepopulated_fields[\"slug\"][0]' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E030'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             prepopulated_fields = {'users': ('name',)}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'prepopulated_fields' refers to 'users', which must not be "
 | |
|             "a DateTimeField, a ForeignKey, a OneToOneField, or a ManyToManyField.",
 | |
|             'admin.E028'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             prepopulated_fields = {'slug': ('name',)}
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_one_to_one_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             prepopulated_fields = {'best_friend': ('name',)}
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'prepopulated_fields' refers to 'best_friend', which must not be "
 | |
|             "a DateTimeField, a ForeignKey, a OneToOneField, or a ManyToManyField.",
 | |
|             'admin.E028'
 | |
|         )
 | |
| 
 | |
| 
 | |
| class ListDisplayTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_display' must be a list or tuple.",
 | |
|             'admin.E107'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_display[0]' refers to 'non_existent_field', "
 | |
|             "which is not a callable, an attribute of 'TestModelAdmin', "
 | |
|             "or an attribute or method on 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E108'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display = ('users',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_display[0]' must not be a ManyToManyField.",
 | |
|             'admin.E109'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         def a_callable(obj):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             def a_method(self, obj):
 | |
|                 pass
 | |
|             list_display = ('name', 'decade_published_in', 'a_method', a_callable)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class ListDisplayLinksCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display_links = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_display_links' must be a list, a tuple, or None.",
 | |
|             'admin.E110'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display_links = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel, (
 | |
|                 "The value of 'list_display_links[0]' refers to "
 | |
|                 "'non_existent_field', which is not defined in 'list_display'."
 | |
|             ), 'admin.E111'
 | |
|         )
 | |
| 
 | |
|     def test_missing_in_list_display(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display_links = ('name',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_display_links[0]' refers to 'name', which is not defined in 'list_display'.",
 | |
|             'admin.E111'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         def a_callable(obj):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             def a_method(self, obj):
 | |
|                 pass
 | |
|             list_display = ('name', 'decade_published_in', 'a_method', a_callable)
 | |
|             list_display_links = ('name', 'decade_published_in', 'a_method', a_callable)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_None_is_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display_links = None
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_list_display_links_check_skipped_if_get_list_display_overridden(self):
 | |
|         """
 | |
|         list_display_links check is skipped if get_list_display() is overridden.
 | |
|         """
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display_links = ['name', 'subtitle']
 | |
| 
 | |
|             def get_list_display(self, request):
 | |
|                 pass
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_list_display_link_checked_for_list_tuple_if_get_list_display_overridden(self):
 | |
|         """
 | |
|         list_display_links is checked for list/tuple/None even if
 | |
|         get_list_display() is overridden.
 | |
|         """
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_display_links = 'non-list/tuple'
 | |
| 
 | |
|             def get_list_display(self, request):
 | |
|                 pass
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_display_links' must be a list, a tuple, or None.",
 | |
|             'admin.E110'
 | |
|         )
 | |
| 
 | |
| 
 | |
| class ListFilterTests(CheckTestCase):
 | |
| 
 | |
|     def test_list_filter_validation(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_filter' must be a list or tuple.",
 | |
|             'admin.E112'
 | |
|         )
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_filter[0]' refers to 'non_existent_field', "
 | |
|             "which does not refer to a Field.",
 | |
|             'admin.E116'
 | |
|         )
 | |
| 
 | |
|     def test_not_filter(self):
 | |
|         class RandomClass(object):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = (RandomClass,)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_filter[0]' must inherit from 'ListFilter'.",
 | |
|             'admin.E113')
 | |
| 
 | |
|     def test_not_filter_again(self):
 | |
|         class RandomClass(object):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = (('is_active', RandomClass),)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_filter[0][1]' must inherit from 'FieldListFilter'.",
 | |
|             'admin.E115'
 | |
|         )
 | |
| 
 | |
|     def test_not_filter_again_again(self):
 | |
|         class AwesomeFilter(SimpleListFilter):
 | |
|             def get_title(self):
 | |
|                 return 'awesomeness'
 | |
| 
 | |
|             def get_choices(self, request):
 | |
|                 return (('bit', 'A bit awesome'), ('very', 'Very awesome'), )
 | |
| 
 | |
|             def get_queryset(self, cl, qs):
 | |
|                 return qs
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = (('is_active', AwesomeFilter),)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_filter[0][1]' must inherit from 'FieldListFilter'.",
 | |
|             'admin.E115'
 | |
|         )
 | |
| 
 | |
|     def test_not_associated_with_field_name(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = (BooleanFieldListFilter,)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_filter[0]' must not inherit from 'FieldListFilter'.",
 | |
|             'admin.E114'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class AwesomeFilter(SimpleListFilter):
 | |
|             def get_title(self):
 | |
|                 return 'awesomeness'
 | |
| 
 | |
|             def get_choices(self, request):
 | |
|                 return (('bit', 'A bit awesome'), ('very', 'Very awesome'), )
 | |
| 
 | |
|             def get_queryset(self, cl, qs):
 | |
|                 return qs
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_filter = ('is_active', AwesomeFilter, ('is_active', BooleanFieldListFilter), 'no')
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class ListPerPageCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_integer(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_per_page = 'hello'
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_per_page' must be an integer.",
 | |
|             'admin.E118'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_per_page = 100
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class ListMaxShowAllCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_integer(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_max_show_all = 'hello'
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_max_show_all' must be an integer.",
 | |
|             'admin.E119'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_max_show_all = 200
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class SearchFieldsCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             search_fields = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'search_fields' must be a list or tuple.",
 | |
|             'admin.E126'
 | |
|         )
 | |
| 
 | |
| 
 | |
| class DateHierarchyCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             date_hierarchy = 'non_existent_field'
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'date_hierarchy' refers to 'non_existent_field', "
 | |
|             "which does not refer to a Field.",
 | |
|             'admin.E127'
 | |
|         )
 | |
| 
 | |
|     def test_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             date_hierarchy = 'name'
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'date_hierarchy' must be a DateField or DateTimeField.",
 | |
|             'admin.E128'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             date_hierarchy = 'pub_date'
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_related_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             date_hierarchy = 'band__sign_date'
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_related_invalid_field_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             date_hierarchy = 'band__name'
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'date_hierarchy' must be a DateField or DateTimeField.",
 | |
|             'admin.E128'
 | |
|         )
 | |
| 
 | |
| 
 | |
| class OrderingCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             ordering = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'ordering' must be a list or tuple.",
 | |
|             'admin.E031'
 | |
|         )
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             ordering = ('non_existent_field',)
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'ordering[0]' refers to 'non_existent_field', "
 | |
|             "which is not an attribute of 'modeladmin.ValidationTestModel'.",
 | |
|             'admin.E033'
 | |
|         )
 | |
| 
 | |
|     def test_random_marker_not_alone(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             ordering = ('?', 'name')
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'ordering' has the random ordering marker '?', but contains "
 | |
|             "other fields as well.",
 | |
|             'admin.E032',
 | |
|             hint='Either remove the "?", or remove the other fields.'
 | |
|         )
 | |
| 
 | |
|     def test_valid_random_marker_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             ordering = ('?',)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_valid_complex_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             ordering = ('band__name',)
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             ordering = ('name', 'pk')
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class ListSelectRelatedCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_invalid_type(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_select_related = 1
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'list_select_related' must be a boolean, tuple or list.",
 | |
|             'admin.E117'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             list_select_related = False
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class SaveAsCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_boolean(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             save_as = 1
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'save_as' must be a boolean.",
 | |
|             'admin.E101'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             save_as = True
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class SaveOnTopCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_boolean(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             save_on_top = 1
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'save_on_top' must be a boolean.",
 | |
|             'admin.E102'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             save_on_top = True
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class InlinesCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_iterable(self):
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = 10
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'inlines' must be a list or tuple.",
 | |
|             'admin.E103'
 | |
|         )
 | |
| 
 | |
|     def test_not_model_admin(self):
 | |
|         class ValidationTestInline(object):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalidRegexp(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             r"'.*\.ValidationTestInline' must inherit from 'InlineModelAdmin'\.",
 | |
|             'admin.E104'
 | |
|         )
 | |
| 
 | |
|     def test_missing_model_field(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             pass
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalidRegexp(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             r"'.*\.ValidationTestInline' must have a 'model' attribute\.",
 | |
|             'admin.E105')
 | |
| 
 | |
|     def test_invalid_model_type(self):
 | |
|         class SomethingBad(object):
 | |
|             pass
 | |
| 
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = SomethingBad
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalidRegexp(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             r"The value of '.*\.ValidationTestInline.model' must be a Model\.",
 | |
|             'admin.E106'
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class FkNameCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_missing_field(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             fk_name = 'non_existent_field'
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "'modeladmin.ValidationTestInlineModel' has no field named 'non_existent_field'.",
 | |
|             'admin.E202',
 | |
|             invalid_obj=ValidationTestInline
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             fk_name = 'parent'
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class ExtraCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_integer(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             extra = 'hello'
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'extra' must be an integer.",
 | |
|             'admin.E203',
 | |
|             invalid_obj=ValidationTestInline
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             extra = 2
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class MaxNumCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_integer(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             max_num = 'hello'
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'max_num' must be an integer.",
 | |
|             'admin.E204',
 | |
|             invalid_obj=ValidationTestInline
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             max_num = 2
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class MinNumCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_not_integer(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             min_num = 'hello'
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'min_num' must be an integer.",
 | |
|             'admin.E205',
 | |
|             invalid_obj=ValidationTestInline
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             min_num = 2
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class FormsetCheckTests(CheckTestCase):
 | |
| 
 | |
|     def test_invalid_type(self):
 | |
|         class FakeFormSet(object):
 | |
|             pass
 | |
| 
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             formset = FakeFormSet
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsInvalid(
 | |
|             TestModelAdmin, ValidationTestModel,
 | |
|             "The value of 'formset' must inherit from 'BaseModelFormSet'.",
 | |
|             'admin.E206',
 | |
|             invalid_obj=ValidationTestInline
 | |
|         )
 | |
| 
 | |
|     def test_valid_case(self):
 | |
|         class RealModelFormSet(BaseModelFormSet):
 | |
|             pass
 | |
| 
 | |
|         class ValidationTestInline(TabularInline):
 | |
|             model = ValidationTestInlineModel
 | |
|             formset = RealModelFormSet
 | |
| 
 | |
|         class TestModelAdmin(ModelAdmin):
 | |
|             inlines = [ValidationTestInline]
 | |
| 
 | |
|         self.assertIsValid(TestModelAdmin, ValidationTestModel)
 | |
| 
 | |
| 
 | |
| class ListDisplayEditableTests(CheckTestCase):
 | |
|     def test_list_display_links_is_none(self):
 | |
|         """
 | |
|         list_display and list_editable can contain the same values
 | |
|         when list_display_links is None
 | |
|         """
 | |
|         class ProductAdmin(ModelAdmin):
 | |
|             list_display = ['name', 'slug', 'pub_date']
 | |
|             list_editable = list_display
 | |
|             list_display_links = None
 | |
|         self.assertIsValid(ProductAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_list_display_first_item_same_as_list_editable_first_item(self):
 | |
|         """
 | |
|         The first item in list_display can be the same as the first in
 | |
|         list_editable.
 | |
|         """
 | |
|         class ProductAdmin(ModelAdmin):
 | |
|             list_display = ['name', 'slug', 'pub_date']
 | |
|             list_editable = ['name', 'slug']
 | |
|             list_display_links = ['pub_date']
 | |
|         self.assertIsValid(ProductAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_list_display_first_item_in_list_editable(self):
 | |
|         """
 | |
|         The first item in list_display can be in list_editable as long as
 | |
|         list_display_links is defined.
 | |
|         """
 | |
|         class ProductAdmin(ModelAdmin):
 | |
|             list_display = ['name', 'slug', 'pub_date']
 | |
|             list_editable = ['slug', 'name']
 | |
|             list_display_links = ['pub_date']
 | |
|         self.assertIsValid(ProductAdmin, ValidationTestModel)
 | |
| 
 | |
|     def test_list_display_first_item_same_as_list_editable_no_list_display_links(self):
 | |
|         """
 | |
|         The first item in list_display cannot be the same as the first item
 | |
|         in list_editable if list_display_links is not defined.
 | |
|         """
 | |
|         class ProductAdmin(ModelAdmin):
 | |
|             list_display = ['name']
 | |
|             list_editable = ['name']
 | |
|         self.assertIsInvalid(
 | |
|             ProductAdmin, ValidationTestModel,
 | |
|             "The value of 'list_editable[0]' refers to the first field "
 | |
|             "in 'list_display' ('name'), which cannot be used unless "
 | |
|             "'list_display_links' is set.",
 | |
|             id='admin.E124',
 | |
|         )
 | |
| 
 | |
|     def test_list_display_first_item_in_list_editable_no_list_display_links(self):
 | |
|         """
 | |
|         The first item in list_display cannot be in list_editable if
 | |
|         list_display_links isn't defined.
 | |
|         """
 | |
|         class ProductAdmin(ModelAdmin):
 | |
|             list_display = ['name', 'slug', 'pub_date']
 | |
|             list_editable = ['slug', 'name']
 | |
|         self.assertIsInvalid(
 | |
|             ProductAdmin, ValidationTestModel,
 | |
|             "The value of 'list_editable[1]' refers to the first field "
 | |
|             "in 'list_display' ('name'), which cannot be used unless "
 | |
|             "'list_display_links' is set.",
 | |
|             id='admin.E124',
 | |
|         )
 |