1. from django import forms
    
  2. from django.contrib import admin
    
  3. from django.contrib.admin import BooleanFieldListFilter, SimpleListFilter
    
  4. from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline
    
  5. from django.contrib.admin.sites import AdminSite
    
  6. from django.core.checks import Error
    
  7. from django.db.models import CASCADE, F, Field, ForeignKey, Model
    
  8. from django.db.models.functions import Upper
    
  9. from django.forms.models import BaseModelFormSet
    
  10. from django.test import SimpleTestCase
    
  11. 
    
  12. from .models import Band, Song, User, ValidationTestInlineModel, ValidationTestModel
    
  13. 
    
  14. 
    
  15. class CheckTestCase(SimpleTestCase):
    
  16.     def assertIsInvalid(
    
  17.         self,
    
  18.         model_admin,
    
  19.         model,
    
  20.         msg,
    
  21.         id=None,
    
  22.         hint=None,
    
  23.         invalid_obj=None,
    
  24.         admin_site=None,
    
  25.     ):
    
  26.         if admin_site is None:
    
  27.             admin_site = AdminSite()
    
  28.         invalid_obj = invalid_obj or model_admin
    
  29.         admin_obj = model_admin(model, admin_site)
    
  30.         self.assertEqual(
    
  31.             admin_obj.check(), [Error(msg, hint=hint, obj=invalid_obj, id=id)]
    
  32.         )
    
  33. 
    
  34.     def assertIsInvalidRegexp(
    
  35.         self, model_admin, model, msg, id=None, hint=None, invalid_obj=None
    
  36.     ):
    
  37.         """
    
  38.         Same as assertIsInvalid but treats the given msg as a regexp.
    
  39.         """
    
  40.         invalid_obj = invalid_obj or model_admin
    
  41.         admin_obj = model_admin(model, AdminSite())
    
  42.         errors = admin_obj.check()
    
  43.         self.assertEqual(len(errors), 1)
    
  44.         error = errors[0]
    
  45.         self.assertEqual(error.hint, hint)
    
  46.         self.assertEqual(error.obj, invalid_obj)
    
  47.         self.assertEqual(error.id, id)
    
  48.         self.assertRegex(error.msg, msg)
    
  49. 
    
  50.     def assertIsValid(self, model_admin, model, admin_site=None):
    
  51.         if admin_site is None:
    
  52.             admin_site = AdminSite()
    
  53.         admin_obj = model_admin(model, admin_site)
    
  54.         self.assertEqual(admin_obj.check(), [])
    
  55. 
    
  56. 
    
  57. class RawIdCheckTests(CheckTestCase):
    
  58.     def test_not_iterable(self):
    
  59.         class TestModelAdmin(ModelAdmin):
    
  60.             raw_id_fields = 10
    
  61. 
    
  62.         self.assertIsInvalid(
    
  63.             TestModelAdmin,
    
  64.             ValidationTestModel,
    
  65.             "The value of 'raw_id_fields' must be a list or tuple.",
    
  66.             "admin.E001",
    
  67.         )
    
  68. 
    
  69.     def test_missing_field(self):
    
  70.         class TestModelAdmin(ModelAdmin):
    
  71.             raw_id_fields = ("non_existent_field",)
    
  72. 
    
  73.         self.assertIsInvalid(
    
  74.             TestModelAdmin,
    
  75.             ValidationTestModel,
    
  76.             "The value of 'raw_id_fields[0]' refers to 'non_existent_field', "
    
  77.             "which is not a field of 'modeladmin.ValidationTestModel'.",
    
  78.             "admin.E002",
    
  79.         )
    
  80. 
    
  81.     def test_invalid_field_type(self):
    
  82.         class TestModelAdmin(ModelAdmin):
    
  83.             raw_id_fields = ("name",)
    
  84. 
    
  85.         self.assertIsInvalid(
    
  86.             TestModelAdmin,
    
  87.             ValidationTestModel,
    
  88.             "The value of 'raw_id_fields[0]' must be a foreign key or a "
    
  89.             "many-to-many field.",
    
  90.             "admin.E003",
    
  91.         )
    
  92. 
    
  93.     def test_valid_case(self):
    
  94.         class TestModelAdmin(ModelAdmin):
    
  95.             raw_id_fields = ("users",)
    
  96. 
    
  97.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  98. 
    
  99.     def test_field_attname(self):
    
  100.         class TestModelAdmin(ModelAdmin):
    
  101.             raw_id_fields = ["band_id"]
    
  102. 
    
  103.         self.assertIsInvalid(
    
  104.             TestModelAdmin,
    
  105.             ValidationTestModel,
    
  106.             "The value of 'raw_id_fields[0]' refers to 'band_id', which is "
    
  107.             "not a field of 'modeladmin.ValidationTestModel'.",
    
  108.             "admin.E002",
    
  109.         )
    
  110. 
    
  111. 
    
  112. class FieldsetsCheckTests(CheckTestCase):
    
  113.     def test_valid_case(self):
    
  114.         class TestModelAdmin(ModelAdmin):
    
  115.             fieldsets = (("General", {"fields": ("name",)}),)
    
  116. 
    
  117.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  118. 
    
  119.     def test_not_iterable(self):
    
  120.         class TestModelAdmin(ModelAdmin):
    
  121.             fieldsets = 10
    
  122. 
    
  123.         self.assertIsInvalid(
    
  124.             TestModelAdmin,
    
  125.             ValidationTestModel,
    
  126.             "The value of 'fieldsets' must be a list or tuple.",
    
  127.             "admin.E007",
    
  128.         )
    
  129. 
    
  130.     def test_non_iterable_item(self):
    
  131.         class TestModelAdmin(ModelAdmin):
    
  132.             fieldsets = ({},)
    
  133. 
    
  134.         self.assertIsInvalid(
    
  135.             TestModelAdmin,
    
  136.             ValidationTestModel,
    
  137.             "The value of 'fieldsets[0]' must be a list or tuple.",
    
  138.             "admin.E008",
    
  139.         )
    
  140. 
    
  141.     def test_item_not_a_pair(self):
    
  142.         class TestModelAdmin(ModelAdmin):
    
  143.             fieldsets = ((),)
    
  144. 
    
  145.         self.assertIsInvalid(
    
  146.             TestModelAdmin,
    
  147.             ValidationTestModel,
    
  148.             "The value of 'fieldsets[0]' must be of length 2.",
    
  149.             "admin.E009",
    
  150.         )
    
  151. 
    
  152.     def test_second_element_of_item_not_a_dict(self):
    
  153.         class TestModelAdmin(ModelAdmin):
    
  154.             fieldsets = (("General", ()),)
    
  155. 
    
  156.         self.assertIsInvalid(
    
  157.             TestModelAdmin,
    
  158.             ValidationTestModel,
    
  159.             "The value of 'fieldsets[0][1]' must be a dictionary.",
    
  160.             "admin.E010",
    
  161.         )
    
  162. 
    
  163.     def test_missing_fields_key(self):
    
  164.         class TestModelAdmin(ModelAdmin):
    
  165.             fieldsets = (("General", {}),)
    
  166. 
    
  167.         self.assertIsInvalid(
    
  168.             TestModelAdmin,
    
  169.             ValidationTestModel,
    
  170.             "The value of 'fieldsets[0][1]' must contain the key 'fields'.",
    
  171.             "admin.E011",
    
  172.         )
    
  173. 
    
  174.         class TestModelAdmin(ModelAdmin):
    
  175.             fieldsets = (("General", {"fields": ("name",)}),)
    
  176. 
    
  177.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  178. 
    
  179.     def test_specified_both_fields_and_fieldsets(self):
    
  180.         class TestModelAdmin(ModelAdmin):
    
  181.             fieldsets = (("General", {"fields": ("name",)}),)
    
  182.             fields = ["name"]
    
  183. 
    
  184.         self.assertIsInvalid(
    
  185.             TestModelAdmin,
    
  186.             ValidationTestModel,
    
  187.             "Both 'fieldsets' and 'fields' are specified.",
    
  188.             "admin.E005",
    
  189.         )
    
  190. 
    
  191.     def test_duplicate_fields(self):
    
  192.         class TestModelAdmin(ModelAdmin):
    
  193.             fieldsets = [(None, {"fields": ["name", "name"]})]
    
  194. 
    
  195.         self.assertIsInvalid(
    
  196.             TestModelAdmin,
    
  197.             ValidationTestModel,
    
  198.             "There are duplicate field(s) in 'fieldsets[0][1]'.",
    
  199.             "admin.E012",
    
  200.         )
    
  201. 
    
  202.     def test_duplicate_fields_in_fieldsets(self):
    
  203.         class TestModelAdmin(ModelAdmin):
    
  204.             fieldsets = [
    
  205.                 (None, {"fields": ["name"]}),
    
  206.                 (None, {"fields": ["name"]}),
    
  207.             ]
    
  208. 
    
  209.         self.assertIsInvalid(
    
  210.             TestModelAdmin,
    
  211.             ValidationTestModel,
    
  212.             "There are duplicate field(s) in 'fieldsets[1][1]'.",
    
  213.             "admin.E012",
    
  214.         )
    
  215. 
    
  216.     def test_fieldsets_with_custom_form_validation(self):
    
  217.         class BandAdmin(ModelAdmin):
    
  218.             fieldsets = (("Band", {"fields": ("name",)}),)
    
  219. 
    
  220.         self.assertIsValid(BandAdmin, Band)
    
  221. 
    
  222. 
    
  223. class FieldsCheckTests(CheckTestCase):
    
  224.     def test_duplicate_fields_in_fields(self):
    
  225.         class TestModelAdmin(ModelAdmin):
    
  226.             fields = ["name", "name"]
    
  227. 
    
  228.         self.assertIsInvalid(
    
  229.             TestModelAdmin,
    
  230.             ValidationTestModel,
    
  231.             "The value of 'fields' contains duplicate field(s).",
    
  232.             "admin.E006",
    
  233.         )
    
  234. 
    
  235.     def test_inline(self):
    
  236.         class ValidationTestInline(TabularInline):
    
  237.             model = ValidationTestInlineModel
    
  238.             fields = 10
    
  239. 
    
  240.         class TestModelAdmin(ModelAdmin):
    
  241.             inlines = [ValidationTestInline]
    
  242. 
    
  243.         self.assertIsInvalid(
    
  244.             TestModelAdmin,
    
  245.             ValidationTestModel,
    
  246.             "The value of 'fields' must be a list or tuple.",
    
  247.             "admin.E004",
    
  248.             invalid_obj=ValidationTestInline,
    
  249.         )
    
  250. 
    
  251. 
    
  252. class FormCheckTests(CheckTestCase):
    
  253.     def test_invalid_type(self):
    
  254.         class FakeForm:
    
  255.             pass
    
  256. 
    
  257.         class TestModelAdmin(ModelAdmin):
    
  258.             form = FakeForm
    
  259. 
    
  260.         class TestModelAdminWithNoForm(ModelAdmin):
    
  261.             form = "not a form"
    
  262. 
    
  263.         for model_admin in (TestModelAdmin, TestModelAdminWithNoForm):
    
  264.             with self.subTest(model_admin):
    
  265.                 self.assertIsInvalid(
    
  266.                     model_admin,
    
  267.                     ValidationTestModel,
    
  268.                     "The value of 'form' must inherit from 'BaseModelForm'.",
    
  269.                     "admin.E016",
    
  270.                 )
    
  271. 
    
  272.     def test_fieldsets_with_custom_form_validation(self):
    
  273.         class BandAdmin(ModelAdmin):
    
  274.             fieldsets = (("Band", {"fields": ("name",)}),)
    
  275. 
    
  276.         self.assertIsValid(BandAdmin, Band)
    
  277. 
    
  278.     def test_valid_case(self):
    
  279.         class AdminBandForm(forms.ModelForm):
    
  280.             delete = forms.BooleanField()
    
  281. 
    
  282.         class BandAdmin(ModelAdmin):
    
  283.             form = AdminBandForm
    
  284.             fieldsets = (("Band", {"fields": ("name", "bio", "sign_date", "delete")}),)
    
  285. 
    
  286.         self.assertIsValid(BandAdmin, Band)
    
  287. 
    
  288. 
    
  289. class FilterVerticalCheckTests(CheckTestCase):
    
  290.     def test_not_iterable(self):
    
  291.         class TestModelAdmin(ModelAdmin):
    
  292.             filter_vertical = 10
    
  293. 
    
  294.         self.assertIsInvalid(
    
  295.             TestModelAdmin,
    
  296.             ValidationTestModel,
    
  297.             "The value of 'filter_vertical' must be a list or tuple.",
    
  298.             "admin.E017",
    
  299.         )
    
  300. 
    
  301.     def test_missing_field(self):
    
  302.         class TestModelAdmin(ModelAdmin):
    
  303.             filter_vertical = ("non_existent_field",)
    
  304. 
    
  305.         self.assertIsInvalid(
    
  306.             TestModelAdmin,
    
  307.             ValidationTestModel,
    
  308.             "The value of 'filter_vertical[0]' refers to 'non_existent_field', "
    
  309.             "which is not a field of 'modeladmin.ValidationTestModel'.",
    
  310.             "admin.E019",
    
  311.         )
    
  312. 
    
  313.     def test_invalid_field_type(self):
    
  314.         class TestModelAdmin(ModelAdmin):
    
  315.             filter_vertical = ("name",)
    
  316. 
    
  317.         self.assertIsInvalid(
    
  318.             TestModelAdmin,
    
  319.             ValidationTestModel,
    
  320.             "The value of 'filter_vertical[0]' must be a many-to-many field.",
    
  321.             "admin.E020",
    
  322.         )
    
  323. 
    
  324.     def test_valid_case(self):
    
  325.         class TestModelAdmin(ModelAdmin):
    
  326.             filter_vertical = ("users",)
    
  327. 
    
  328.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  329. 
    
  330. 
    
  331. class FilterHorizontalCheckTests(CheckTestCase):
    
  332.     def test_not_iterable(self):
    
  333.         class TestModelAdmin(ModelAdmin):
    
  334.             filter_horizontal = 10
    
  335. 
    
  336.         self.assertIsInvalid(
    
  337.             TestModelAdmin,
    
  338.             ValidationTestModel,
    
  339.             "The value of 'filter_horizontal' must be a list or tuple.",
    
  340.             "admin.E018",
    
  341.         )
    
  342. 
    
  343.     def test_missing_field(self):
    
  344.         class TestModelAdmin(ModelAdmin):
    
  345.             filter_horizontal = ("non_existent_field",)
    
  346. 
    
  347.         self.assertIsInvalid(
    
  348.             TestModelAdmin,
    
  349.             ValidationTestModel,
    
  350.             "The value of 'filter_horizontal[0]' refers to 'non_existent_field', "
    
  351.             "which is not a field of 'modeladmin.ValidationTestModel'.",
    
  352.             "admin.E019",
    
  353.         )
    
  354. 
    
  355.     def test_invalid_field_type(self):
    
  356.         class TestModelAdmin(ModelAdmin):
    
  357.             filter_horizontal = ("name",)
    
  358. 
    
  359.         self.assertIsInvalid(
    
  360.             TestModelAdmin,
    
  361.             ValidationTestModel,
    
  362.             "The value of 'filter_horizontal[0]' must be a many-to-many field.",
    
  363.             "admin.E020",
    
  364.         )
    
  365. 
    
  366.     def test_valid_case(self):
    
  367.         class TestModelAdmin(ModelAdmin):
    
  368.             filter_horizontal = ("users",)
    
  369. 
    
  370.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  371. 
    
  372. 
    
  373. class RadioFieldsCheckTests(CheckTestCase):
    
  374.     def test_not_dictionary(self):
    
  375.         class TestModelAdmin(ModelAdmin):
    
  376.             radio_fields = ()
    
  377. 
    
  378.         self.assertIsInvalid(
    
  379.             TestModelAdmin,
    
  380.             ValidationTestModel,
    
  381.             "The value of 'radio_fields' must be a dictionary.",
    
  382.             "admin.E021",
    
  383.         )
    
  384. 
    
  385.     def test_missing_field(self):
    
  386.         class TestModelAdmin(ModelAdmin):
    
  387.             radio_fields = {"non_existent_field": VERTICAL}
    
  388. 
    
  389.         self.assertIsInvalid(
    
  390.             TestModelAdmin,
    
  391.             ValidationTestModel,
    
  392.             "The value of 'radio_fields' refers to 'non_existent_field', "
    
  393.             "which is not a field of 'modeladmin.ValidationTestModel'.",
    
  394.             "admin.E022",
    
  395.         )
    
  396. 
    
  397.     def test_invalid_field_type(self):
    
  398.         class TestModelAdmin(ModelAdmin):
    
  399.             radio_fields = {"name": VERTICAL}
    
  400. 
    
  401.         self.assertIsInvalid(
    
  402.             TestModelAdmin,
    
  403.             ValidationTestModel,
    
  404.             "The value of 'radio_fields' refers to 'name', which is not an instance "
    
  405.             "of ForeignKey, and does not have a 'choices' definition.",
    
  406.             "admin.E023",
    
  407.         )
    
  408. 
    
  409.     def test_invalid_value(self):
    
  410.         class TestModelAdmin(ModelAdmin):
    
  411.             radio_fields = {"state": None}
    
  412. 
    
  413.         self.assertIsInvalid(
    
  414.             TestModelAdmin,
    
  415.             ValidationTestModel,
    
  416.             "The value of 'radio_fields[\"state\"]' must be either admin.HORIZONTAL or "
    
  417.             "admin.VERTICAL.",
    
  418.             "admin.E024",
    
  419.         )
    
  420. 
    
  421.     def test_valid_case(self):
    
  422.         class TestModelAdmin(ModelAdmin):
    
  423.             radio_fields = {"state": VERTICAL}
    
  424. 
    
  425.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  426. 
    
  427. 
    
  428. class PrepopulatedFieldsCheckTests(CheckTestCase):
    
  429.     def test_not_list_or_tuple(self):
    
  430.         class TestModelAdmin(ModelAdmin):
    
  431.             prepopulated_fields = {"slug": "test"}
    
  432. 
    
  433.         self.assertIsInvalid(
    
  434.             TestModelAdmin,
    
  435.             ValidationTestModel,
    
  436.             "The value of 'prepopulated_fields[\"slug\"]' must be a list or tuple.",
    
  437.             "admin.E029",
    
  438.         )
    
  439. 
    
  440.     def test_not_dictionary(self):
    
  441.         class TestModelAdmin(ModelAdmin):
    
  442.             prepopulated_fields = ()
    
  443. 
    
  444.         self.assertIsInvalid(
    
  445.             TestModelAdmin,
    
  446.             ValidationTestModel,
    
  447.             "The value of 'prepopulated_fields' must be a dictionary.",
    
  448.             "admin.E026",
    
  449.         )
    
  450. 
    
  451.     def test_missing_field(self):
    
  452.         class TestModelAdmin(ModelAdmin):
    
  453.             prepopulated_fields = {"non_existent_field": ("slug",)}
    
  454. 
    
  455.         self.assertIsInvalid(
    
  456.             TestModelAdmin,
    
  457.             ValidationTestModel,
    
  458.             "The value of 'prepopulated_fields' refers to 'non_existent_field', "
    
  459.             "which is not a field of 'modeladmin.ValidationTestModel'.",
    
  460.             "admin.E027",
    
  461.         )
    
  462. 
    
  463.     def test_missing_field_again(self):
    
  464.         class TestModelAdmin(ModelAdmin):
    
  465.             prepopulated_fields = {"slug": ("non_existent_field",)}
    
  466. 
    
  467.         self.assertIsInvalid(
    
  468.             TestModelAdmin,
    
  469.             ValidationTestModel,
    
  470.             "The value of 'prepopulated_fields[\"slug\"][0]' refers to "
    
  471.             "'non_existent_field', which is not a field of "
    
  472.             "'modeladmin.ValidationTestModel'.",
    
  473.             "admin.E030",
    
  474.         )
    
  475. 
    
  476.     def test_invalid_field_type(self):
    
  477.         class TestModelAdmin(ModelAdmin):
    
  478.             prepopulated_fields = {"users": ("name",)}
    
  479. 
    
  480.         self.assertIsInvalid(
    
  481.             TestModelAdmin,
    
  482.             ValidationTestModel,
    
  483.             "The value of 'prepopulated_fields' refers to 'users', which must not be "
    
  484.             "a DateTimeField, a ForeignKey, a OneToOneField, or a ManyToManyField.",
    
  485.             "admin.E028",
    
  486.         )
    
  487. 
    
  488.     def test_valid_case(self):
    
  489.         class TestModelAdmin(ModelAdmin):
    
  490.             prepopulated_fields = {"slug": ("name",)}
    
  491. 
    
  492.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  493. 
    
  494.     def test_one_to_one_field(self):
    
  495.         class TestModelAdmin(ModelAdmin):
    
  496.             prepopulated_fields = {"best_friend": ("name",)}
    
  497. 
    
  498.         self.assertIsInvalid(
    
  499.             TestModelAdmin,
    
  500.             ValidationTestModel,
    
  501.             "The value of 'prepopulated_fields' refers to 'best_friend', which must "
    
  502.             "not be a DateTimeField, a ForeignKey, a OneToOneField, or a "
    
  503.             "ManyToManyField.",
    
  504.             "admin.E028",
    
  505.         )
    
  506. 
    
  507. 
    
  508. class ListDisplayTests(CheckTestCase):
    
  509.     def test_not_iterable(self):
    
  510.         class TestModelAdmin(ModelAdmin):
    
  511.             list_display = 10
    
  512. 
    
  513.         self.assertIsInvalid(
    
  514.             TestModelAdmin,
    
  515.             ValidationTestModel,
    
  516.             "The value of 'list_display' must be a list or tuple.",
    
  517.             "admin.E107",
    
  518.         )
    
  519. 
    
  520.     def test_missing_field(self):
    
  521.         class TestModelAdmin(ModelAdmin):
    
  522.             list_display = ("non_existent_field",)
    
  523. 
    
  524.         self.assertIsInvalid(
    
  525.             TestModelAdmin,
    
  526.             ValidationTestModel,
    
  527.             "The value of 'list_display[0]' refers to 'non_existent_field', "
    
  528.             "which is not a callable, an attribute of 'TestModelAdmin', "
    
  529.             "or an attribute or method on 'modeladmin.ValidationTestModel'.",
    
  530.             "admin.E108",
    
  531.         )
    
  532. 
    
  533.     def test_invalid_field_type(self):
    
  534.         class TestModelAdmin(ModelAdmin):
    
  535.             list_display = ("users",)
    
  536. 
    
  537.         self.assertIsInvalid(
    
  538.             TestModelAdmin,
    
  539.             ValidationTestModel,
    
  540.             "The value of 'list_display[0]' must not be a ManyToManyField.",
    
  541.             "admin.E109",
    
  542.         )
    
  543. 
    
  544.     def test_valid_case(self):
    
  545.         @admin.display
    
  546.         def a_callable(obj):
    
  547.             pass
    
  548. 
    
  549.         class TestModelAdmin(ModelAdmin):
    
  550.             @admin.display
    
  551.             def a_method(self, obj):
    
  552.                 pass
    
  553. 
    
  554.             list_display = ("name", "decade_published_in", "a_method", a_callable)
    
  555. 
    
  556.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  557. 
    
  558.     def test_valid_field_accessible_via_instance(self):
    
  559.         class PositionField(Field):
    
  560.             """Custom field accessible only via instance."""
    
  561. 
    
  562.             def contribute_to_class(self, cls, name):
    
  563.                 super().contribute_to_class(cls, name)
    
  564.                 setattr(cls, self.name, self)
    
  565. 
    
  566.             def __get__(self, instance, owner):
    
  567.                 if instance is None:
    
  568.                     raise AttributeError()
    
  569. 
    
  570.         class TestModel(Model):
    
  571.             field = PositionField()
    
  572. 
    
  573.         class TestModelAdmin(ModelAdmin):
    
  574.             list_display = ("field",)
    
  575. 
    
  576.         self.assertIsValid(TestModelAdmin, TestModel)
    
  577. 
    
  578. 
    
  579. class ListDisplayLinksCheckTests(CheckTestCase):
    
  580.     def test_not_iterable(self):
    
  581.         class TestModelAdmin(ModelAdmin):
    
  582.             list_display_links = 10
    
  583. 
    
  584.         self.assertIsInvalid(
    
  585.             TestModelAdmin,
    
  586.             ValidationTestModel,
    
  587.             "The value of 'list_display_links' must be a list, a tuple, or None.",
    
  588.             "admin.E110",
    
  589.         )
    
  590. 
    
  591.     def test_missing_field(self):
    
  592.         class TestModelAdmin(ModelAdmin):
    
  593.             list_display_links = ("non_existent_field",)
    
  594. 
    
  595.         self.assertIsInvalid(
    
  596.             TestModelAdmin,
    
  597.             ValidationTestModel,
    
  598.             (
    
  599.                 "The value of 'list_display_links[0]' refers to "
    
  600.                 "'non_existent_field', which is not defined in 'list_display'."
    
  601.             ),
    
  602.             "admin.E111",
    
  603.         )
    
  604. 
    
  605.     def test_missing_in_list_display(self):
    
  606.         class TestModelAdmin(ModelAdmin):
    
  607.             list_display_links = ("name",)
    
  608. 
    
  609.         self.assertIsInvalid(
    
  610.             TestModelAdmin,
    
  611.             ValidationTestModel,
    
  612.             "The value of 'list_display_links[0]' refers to 'name', which is not "
    
  613.             "defined in 'list_display'.",
    
  614.             "admin.E111",
    
  615.         )
    
  616. 
    
  617.     def test_valid_case(self):
    
  618.         @admin.display
    
  619.         def a_callable(obj):
    
  620.             pass
    
  621. 
    
  622.         class TestModelAdmin(ModelAdmin):
    
  623.             @admin.display
    
  624.             def a_method(self, obj):
    
  625.                 pass
    
  626. 
    
  627.             list_display = ("name", "decade_published_in", "a_method", a_callable)
    
  628.             list_display_links = ("name", "decade_published_in", "a_method", a_callable)
    
  629. 
    
  630.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  631. 
    
  632.     def test_None_is_valid_case(self):
    
  633.         class TestModelAdmin(ModelAdmin):
    
  634.             list_display_links = None
    
  635. 
    
  636.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  637. 
    
  638.     def test_list_display_links_check_skipped_if_get_list_display_overridden(self):
    
  639.         """
    
  640.         list_display_links check is skipped if get_list_display() is overridden.
    
  641.         """
    
  642. 
    
  643.         class TestModelAdmin(ModelAdmin):
    
  644.             list_display_links = ["name", "subtitle"]
    
  645. 
    
  646.             def get_list_display(self, request):
    
  647.                 pass
    
  648. 
    
  649.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  650. 
    
  651.     def test_list_display_link_checked_for_list_tuple_if_get_list_display_overridden(
    
  652.         self,
    
  653.     ):
    
  654.         """
    
  655.         list_display_links is checked for list/tuple/None even if
    
  656.         get_list_display() is overridden.
    
  657.         """
    
  658. 
    
  659.         class TestModelAdmin(ModelAdmin):
    
  660.             list_display_links = "non-list/tuple"
    
  661. 
    
  662.             def get_list_display(self, request):
    
  663.                 pass
    
  664. 
    
  665.         self.assertIsInvalid(
    
  666.             TestModelAdmin,
    
  667.             ValidationTestModel,
    
  668.             "The value of 'list_display_links' must be a list, a tuple, or None.",
    
  669.             "admin.E110",
    
  670.         )
    
  671. 
    
  672. 
    
  673. class ListFilterTests(CheckTestCase):
    
  674.     def test_list_filter_validation(self):
    
  675.         class TestModelAdmin(ModelAdmin):
    
  676.             list_filter = 10
    
  677. 
    
  678.         self.assertIsInvalid(
    
  679.             TestModelAdmin,
    
  680.             ValidationTestModel,
    
  681.             "The value of 'list_filter' must be a list or tuple.",
    
  682.             "admin.E112",
    
  683.         )
    
  684. 
    
  685.     def test_not_list_filter_class(self):
    
  686.         class TestModelAdmin(ModelAdmin):
    
  687.             list_filter = ["RandomClass"]
    
  688. 
    
  689.         self.assertIsInvalid(
    
  690.             TestModelAdmin,
    
  691.             ValidationTestModel,
    
  692.             "The value of 'list_filter[0]' refers to 'RandomClass', which "
    
  693.             "does not refer to a Field.",
    
  694.             "admin.E116",
    
  695.         )
    
  696. 
    
  697.     def test_callable(self):
    
  698.         def random_callable():
    
  699.             pass
    
  700. 
    
  701.         class TestModelAdmin(ModelAdmin):
    
  702.             list_filter = [random_callable]
    
  703. 
    
  704.         self.assertIsInvalid(
    
  705.             TestModelAdmin,
    
  706.             ValidationTestModel,
    
  707.             "The value of 'list_filter[0]' must inherit from 'ListFilter'.",
    
  708.             "admin.E113",
    
  709.         )
    
  710. 
    
  711.     def test_not_callable(self):
    
  712.         class TestModelAdmin(ModelAdmin):
    
  713.             list_filter = [[42, 42]]
    
  714. 
    
  715.         self.assertIsInvalid(
    
  716.             TestModelAdmin,
    
  717.             ValidationTestModel,
    
  718.             "The value of 'list_filter[0][1]' must inherit from 'FieldListFilter'.",
    
  719.             "admin.E115",
    
  720.         )
    
  721. 
    
  722.     def test_missing_field(self):
    
  723.         class TestModelAdmin(ModelAdmin):
    
  724.             list_filter = ("non_existent_field",)
    
  725. 
    
  726.         self.assertIsInvalid(
    
  727.             TestModelAdmin,
    
  728.             ValidationTestModel,
    
  729.             "The value of 'list_filter[0]' refers to 'non_existent_field', "
    
  730.             "which does not refer to a Field.",
    
  731.             "admin.E116",
    
  732.         )
    
  733. 
    
  734.     def test_not_filter(self):
    
  735.         class RandomClass:
    
  736.             pass
    
  737. 
    
  738.         class TestModelAdmin(ModelAdmin):
    
  739.             list_filter = (RandomClass,)
    
  740. 
    
  741.         self.assertIsInvalid(
    
  742.             TestModelAdmin,
    
  743.             ValidationTestModel,
    
  744.             "The value of 'list_filter[0]' must inherit from 'ListFilter'.",
    
  745.             "admin.E113",
    
  746.         )
    
  747. 
    
  748.     def test_not_filter_again(self):
    
  749.         class RandomClass:
    
  750.             pass
    
  751. 
    
  752.         class TestModelAdmin(ModelAdmin):
    
  753.             list_filter = (("is_active", RandomClass),)
    
  754. 
    
  755.         self.assertIsInvalid(
    
  756.             TestModelAdmin,
    
  757.             ValidationTestModel,
    
  758.             "The value of 'list_filter[0][1]' must inherit from 'FieldListFilter'.",
    
  759.             "admin.E115",
    
  760.         )
    
  761. 
    
  762.     def test_not_filter_again_again(self):
    
  763.         class AwesomeFilter(SimpleListFilter):
    
  764.             def get_title(self):
    
  765.                 return "awesomeness"
    
  766. 
    
  767.             def get_choices(self, request):
    
  768.                 return (("bit", "A bit awesome"), ("very", "Very awesome"))
    
  769. 
    
  770.             def get_queryset(self, cl, qs):
    
  771.                 return qs
    
  772. 
    
  773.         class TestModelAdmin(ModelAdmin):
    
  774.             list_filter = (("is_active", AwesomeFilter),)
    
  775. 
    
  776.         self.assertIsInvalid(
    
  777.             TestModelAdmin,
    
  778.             ValidationTestModel,
    
  779.             "The value of 'list_filter[0][1]' must inherit from 'FieldListFilter'.",
    
  780.             "admin.E115",
    
  781.         )
    
  782. 
    
  783.     def test_list_filter_is_func(self):
    
  784.         def get_filter():
    
  785.             pass
    
  786. 
    
  787.         class TestModelAdmin(ModelAdmin):
    
  788.             list_filter = [get_filter]
    
  789. 
    
  790.         self.assertIsInvalid(
    
  791.             TestModelAdmin,
    
  792.             ValidationTestModel,
    
  793.             "The value of 'list_filter[0]' must inherit from 'ListFilter'.",
    
  794.             "admin.E113",
    
  795.         )
    
  796. 
    
  797.     def test_not_associated_with_field_name(self):
    
  798.         class TestModelAdmin(ModelAdmin):
    
  799.             list_filter = (BooleanFieldListFilter,)
    
  800. 
    
  801.         self.assertIsInvalid(
    
  802.             TestModelAdmin,
    
  803.             ValidationTestModel,
    
  804.             "The value of 'list_filter[0]' must not inherit from 'FieldListFilter'.",
    
  805.             "admin.E114",
    
  806.         )
    
  807. 
    
  808.     def test_valid_case(self):
    
  809.         class AwesomeFilter(SimpleListFilter):
    
  810.             def get_title(self):
    
  811.                 return "awesomeness"
    
  812. 
    
  813.             def get_choices(self, request):
    
  814.                 return (("bit", "A bit awesome"), ("very", "Very awesome"))
    
  815. 
    
  816.             def get_queryset(self, cl, qs):
    
  817.                 return qs
    
  818. 
    
  819.         class TestModelAdmin(ModelAdmin):
    
  820.             list_filter = (
    
  821.                 "is_active",
    
  822.                 AwesomeFilter,
    
  823.                 ("is_active", BooleanFieldListFilter),
    
  824.                 "no",
    
  825.             )
    
  826. 
    
  827.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  828. 
    
  829. 
    
  830. class ListPerPageCheckTests(CheckTestCase):
    
  831.     def test_not_integer(self):
    
  832.         class TestModelAdmin(ModelAdmin):
    
  833.             list_per_page = "hello"
    
  834. 
    
  835.         self.assertIsInvalid(
    
  836.             TestModelAdmin,
    
  837.             ValidationTestModel,
    
  838.             "The value of 'list_per_page' must be an integer.",
    
  839.             "admin.E118",
    
  840.         )
    
  841. 
    
  842.     def test_valid_case(self):
    
  843.         class TestModelAdmin(ModelAdmin):
    
  844.             list_per_page = 100
    
  845. 
    
  846.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  847. 
    
  848. 
    
  849. class ListMaxShowAllCheckTests(CheckTestCase):
    
  850.     def test_not_integer(self):
    
  851.         class TestModelAdmin(ModelAdmin):
    
  852.             list_max_show_all = "hello"
    
  853. 
    
  854.         self.assertIsInvalid(
    
  855.             TestModelAdmin,
    
  856.             ValidationTestModel,
    
  857.             "The value of 'list_max_show_all' must be an integer.",
    
  858.             "admin.E119",
    
  859.         )
    
  860. 
    
  861.     def test_valid_case(self):
    
  862.         class TestModelAdmin(ModelAdmin):
    
  863.             list_max_show_all = 200
    
  864. 
    
  865.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  866. 
    
  867. 
    
  868. class SearchFieldsCheckTests(CheckTestCase):
    
  869.     def test_not_iterable(self):
    
  870.         class TestModelAdmin(ModelAdmin):
    
  871.             search_fields = 10
    
  872. 
    
  873.         self.assertIsInvalid(
    
  874.             TestModelAdmin,
    
  875.             ValidationTestModel,
    
  876.             "The value of 'search_fields' must be a list or tuple.",
    
  877.             "admin.E126",
    
  878.         )
    
  879. 
    
  880. 
    
  881. class DateHierarchyCheckTests(CheckTestCase):
    
  882.     def test_missing_field(self):
    
  883.         class TestModelAdmin(ModelAdmin):
    
  884.             date_hierarchy = "non_existent_field"
    
  885. 
    
  886.         self.assertIsInvalid(
    
  887.             TestModelAdmin,
    
  888.             ValidationTestModel,
    
  889.             "The value of 'date_hierarchy' refers to 'non_existent_field', "
    
  890.             "which does not refer to a Field.",
    
  891.             "admin.E127",
    
  892.         )
    
  893. 
    
  894.     def test_invalid_field_type(self):
    
  895.         class TestModelAdmin(ModelAdmin):
    
  896.             date_hierarchy = "name"
    
  897. 
    
  898.         self.assertIsInvalid(
    
  899.             TestModelAdmin,
    
  900.             ValidationTestModel,
    
  901.             "The value of 'date_hierarchy' must be a DateField or DateTimeField.",
    
  902.             "admin.E128",
    
  903.         )
    
  904. 
    
  905.     def test_valid_case(self):
    
  906.         class TestModelAdmin(ModelAdmin):
    
  907.             date_hierarchy = "pub_date"
    
  908. 
    
  909.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  910. 
    
  911.     def test_related_valid_case(self):
    
  912.         class TestModelAdmin(ModelAdmin):
    
  913.             date_hierarchy = "band__sign_date"
    
  914. 
    
  915.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  916. 
    
  917.     def test_related_invalid_field_type(self):
    
  918.         class TestModelAdmin(ModelAdmin):
    
  919.             date_hierarchy = "band__name"
    
  920. 
    
  921.         self.assertIsInvalid(
    
  922.             TestModelAdmin,
    
  923.             ValidationTestModel,
    
  924.             "The value of 'date_hierarchy' must be a DateField or DateTimeField.",
    
  925.             "admin.E128",
    
  926.         )
    
  927. 
    
  928. 
    
  929. class OrderingCheckTests(CheckTestCase):
    
  930.     def test_not_iterable(self):
    
  931.         class TestModelAdmin(ModelAdmin):
    
  932.             ordering = 10
    
  933. 
    
  934.         self.assertIsInvalid(
    
  935.             TestModelAdmin,
    
  936.             ValidationTestModel,
    
  937.             "The value of 'ordering' must be a list or tuple.",
    
  938.             "admin.E031",
    
  939.         )
    
  940. 
    
  941.         class TestModelAdmin(ModelAdmin):
    
  942.             ordering = ("non_existent_field",)
    
  943. 
    
  944.         self.assertIsInvalid(
    
  945.             TestModelAdmin,
    
  946.             ValidationTestModel,
    
  947.             "The value of 'ordering[0]' refers to 'non_existent_field', "
    
  948.             "which is not a field of 'modeladmin.ValidationTestModel'.",
    
  949.             "admin.E033",
    
  950.         )
    
  951. 
    
  952.     def test_random_marker_not_alone(self):
    
  953.         class TestModelAdmin(ModelAdmin):
    
  954.             ordering = ("?", "name")
    
  955. 
    
  956.         self.assertIsInvalid(
    
  957.             TestModelAdmin,
    
  958.             ValidationTestModel,
    
  959.             "The value of 'ordering' has the random ordering marker '?', but contains "
    
  960.             "other fields as well.",
    
  961.             "admin.E032",
    
  962.             hint='Either remove the "?", or remove the other fields.',
    
  963.         )
    
  964. 
    
  965.     def test_valid_random_marker_case(self):
    
  966.         class TestModelAdmin(ModelAdmin):
    
  967.             ordering = ("?",)
    
  968. 
    
  969.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  970. 
    
  971.     def test_valid_complex_case(self):
    
  972.         class TestModelAdmin(ModelAdmin):
    
  973.             ordering = ("band__name",)
    
  974. 
    
  975.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  976. 
    
  977.     def test_valid_case(self):
    
  978.         class TestModelAdmin(ModelAdmin):
    
  979.             ordering = ("name", "pk")
    
  980. 
    
  981.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  982. 
    
  983.     def test_invalid_expression(self):
    
  984.         class TestModelAdmin(ModelAdmin):
    
  985.             ordering = (F("nonexistent"),)
    
  986. 
    
  987.         self.assertIsInvalid(
    
  988.             TestModelAdmin,
    
  989.             ValidationTestModel,
    
  990.             "The value of 'ordering[0]' refers to 'nonexistent', which is not "
    
  991.             "a field of 'modeladmin.ValidationTestModel'.",
    
  992.             "admin.E033",
    
  993.         )
    
  994. 
    
  995.     def test_valid_expression(self):
    
  996.         class TestModelAdmin(ModelAdmin):
    
  997.             ordering = (Upper("name"), Upper("band__name").desc())
    
  998. 
    
  999.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1000. 
    
  1001. 
    
  1002. class ListSelectRelatedCheckTests(CheckTestCase):
    
  1003.     def test_invalid_type(self):
    
  1004.         class TestModelAdmin(ModelAdmin):
    
  1005.             list_select_related = 1
    
  1006. 
    
  1007.         self.assertIsInvalid(
    
  1008.             TestModelAdmin,
    
  1009.             ValidationTestModel,
    
  1010.             "The value of 'list_select_related' must be a boolean, tuple or list.",
    
  1011.             "admin.E117",
    
  1012.         )
    
  1013. 
    
  1014.     def test_valid_case(self):
    
  1015.         class TestModelAdmin(ModelAdmin):
    
  1016.             list_select_related = False
    
  1017. 
    
  1018.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1019. 
    
  1020. 
    
  1021. class SaveAsCheckTests(CheckTestCase):
    
  1022.     def test_not_boolean(self):
    
  1023.         class TestModelAdmin(ModelAdmin):
    
  1024.             save_as = 1
    
  1025. 
    
  1026.         self.assertIsInvalid(
    
  1027.             TestModelAdmin,
    
  1028.             ValidationTestModel,
    
  1029.             "The value of 'save_as' must be a boolean.",
    
  1030.             "admin.E101",
    
  1031.         )
    
  1032. 
    
  1033.     def test_valid_case(self):
    
  1034.         class TestModelAdmin(ModelAdmin):
    
  1035.             save_as = True
    
  1036. 
    
  1037.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1038. 
    
  1039. 
    
  1040. class SaveOnTopCheckTests(CheckTestCase):
    
  1041.     def test_not_boolean(self):
    
  1042.         class TestModelAdmin(ModelAdmin):
    
  1043.             save_on_top = 1
    
  1044. 
    
  1045.         self.assertIsInvalid(
    
  1046.             TestModelAdmin,
    
  1047.             ValidationTestModel,
    
  1048.             "The value of 'save_on_top' must be a boolean.",
    
  1049.             "admin.E102",
    
  1050.         )
    
  1051. 
    
  1052.     def test_valid_case(self):
    
  1053.         class TestModelAdmin(ModelAdmin):
    
  1054.             save_on_top = True
    
  1055. 
    
  1056.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1057. 
    
  1058. 
    
  1059. class InlinesCheckTests(CheckTestCase):
    
  1060.     def test_not_iterable(self):
    
  1061.         class TestModelAdmin(ModelAdmin):
    
  1062.             inlines = 10
    
  1063. 
    
  1064.         self.assertIsInvalid(
    
  1065.             TestModelAdmin,
    
  1066.             ValidationTestModel,
    
  1067.             "The value of 'inlines' must be a list or tuple.",
    
  1068.             "admin.E103",
    
  1069.         )
    
  1070. 
    
  1071.     def test_not_correct_inline_field(self):
    
  1072.         class TestModelAdmin(ModelAdmin):
    
  1073.             inlines = [42]
    
  1074. 
    
  1075.         self.assertIsInvalidRegexp(
    
  1076.             TestModelAdmin,
    
  1077.             ValidationTestModel,
    
  1078.             r"'.*\.TestModelAdmin' must inherit from 'InlineModelAdmin'\.",
    
  1079.             "admin.E104",
    
  1080.         )
    
  1081. 
    
  1082.     def test_not_model_admin(self):
    
  1083.         class ValidationTestInline:
    
  1084.             pass
    
  1085. 
    
  1086.         class TestModelAdmin(ModelAdmin):
    
  1087.             inlines = [ValidationTestInline]
    
  1088. 
    
  1089.         self.assertIsInvalidRegexp(
    
  1090.             TestModelAdmin,
    
  1091.             ValidationTestModel,
    
  1092.             r"'.*\.ValidationTestInline' must inherit from 'InlineModelAdmin'\.",
    
  1093.             "admin.E104",
    
  1094.         )
    
  1095. 
    
  1096.     def test_missing_model_field(self):
    
  1097.         class ValidationTestInline(TabularInline):
    
  1098.             pass
    
  1099. 
    
  1100.         class TestModelAdmin(ModelAdmin):
    
  1101.             inlines = [ValidationTestInline]
    
  1102. 
    
  1103.         self.assertIsInvalidRegexp(
    
  1104.             TestModelAdmin,
    
  1105.             ValidationTestModel,
    
  1106.             r"'.*\.ValidationTestInline' must have a 'model' attribute\.",
    
  1107.             "admin.E105",
    
  1108.         )
    
  1109. 
    
  1110.     def test_invalid_model_type(self):
    
  1111.         class SomethingBad:
    
  1112.             pass
    
  1113. 
    
  1114.         class ValidationTestInline(TabularInline):
    
  1115.             model = SomethingBad
    
  1116. 
    
  1117.         class TestModelAdmin(ModelAdmin):
    
  1118.             inlines = [ValidationTestInline]
    
  1119. 
    
  1120.         self.assertIsInvalidRegexp(
    
  1121.             TestModelAdmin,
    
  1122.             ValidationTestModel,
    
  1123.             r"The value of '.*\.ValidationTestInline.model' must be a Model\.",
    
  1124.             "admin.E106",
    
  1125.         )
    
  1126. 
    
  1127.     def test_invalid_model(self):
    
  1128.         class ValidationTestInline(TabularInline):
    
  1129.             model = "Not a class"
    
  1130. 
    
  1131.         class TestModelAdmin(ModelAdmin):
    
  1132.             inlines = [ValidationTestInline]
    
  1133. 
    
  1134.         self.assertIsInvalidRegexp(
    
  1135.             TestModelAdmin,
    
  1136.             ValidationTestModel,
    
  1137.             r"The value of '.*\.ValidationTestInline.model' must be a Model\.",
    
  1138.             "admin.E106",
    
  1139.         )
    
  1140. 
    
  1141.     def test_invalid_callable(self):
    
  1142.         def random_obj():
    
  1143.             pass
    
  1144. 
    
  1145.         class TestModelAdmin(ModelAdmin):
    
  1146.             inlines = [random_obj]
    
  1147. 
    
  1148.         self.assertIsInvalidRegexp(
    
  1149.             TestModelAdmin,
    
  1150.             ValidationTestModel,
    
  1151.             r"'.*\.random_obj' must inherit from 'InlineModelAdmin'\.",
    
  1152.             "admin.E104",
    
  1153.         )
    
  1154. 
    
  1155.     def test_valid_case(self):
    
  1156.         class ValidationTestInline(TabularInline):
    
  1157.             model = ValidationTestInlineModel
    
  1158. 
    
  1159.         class TestModelAdmin(ModelAdmin):
    
  1160.             inlines = [ValidationTestInline]
    
  1161. 
    
  1162.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1163. 
    
  1164. 
    
  1165. class FkNameCheckTests(CheckTestCase):
    
  1166.     def test_missing_field(self):
    
  1167.         class ValidationTestInline(TabularInline):
    
  1168.             model = ValidationTestInlineModel
    
  1169.             fk_name = "non_existent_field"
    
  1170. 
    
  1171.         class TestModelAdmin(ModelAdmin):
    
  1172.             inlines = [ValidationTestInline]
    
  1173. 
    
  1174.         self.assertIsInvalid(
    
  1175.             TestModelAdmin,
    
  1176.             ValidationTestModel,
    
  1177.             "'modeladmin.ValidationTestInlineModel' has no field named "
    
  1178.             "'non_existent_field'.",
    
  1179.             "admin.E202",
    
  1180.             invalid_obj=ValidationTestInline,
    
  1181.         )
    
  1182. 
    
  1183.     def test_valid_case(self):
    
  1184.         class ValidationTestInline(TabularInline):
    
  1185.             model = ValidationTestInlineModel
    
  1186.             fk_name = "parent"
    
  1187. 
    
  1188.         class TestModelAdmin(ModelAdmin):
    
  1189.             inlines = [ValidationTestInline]
    
  1190. 
    
  1191.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1192. 
    
  1193.     def test_proxy_model_parent(self):
    
  1194.         class Parent(Model):
    
  1195.             pass
    
  1196. 
    
  1197.         class ProxyChild(Parent):
    
  1198.             class Meta:
    
  1199.                 proxy = True
    
  1200. 
    
  1201.         class ProxyProxyChild(ProxyChild):
    
  1202.             class Meta:
    
  1203.                 proxy = True
    
  1204. 
    
  1205.         class Related(Model):
    
  1206.             proxy_child = ForeignKey(ProxyChild, on_delete=CASCADE)
    
  1207. 
    
  1208.         class InlineFkName(admin.TabularInline):
    
  1209.             model = Related
    
  1210.             fk_name = "proxy_child"
    
  1211. 
    
  1212.         class InlineNoFkName(admin.TabularInline):
    
  1213.             model = Related
    
  1214. 
    
  1215.         class ProxyProxyChildAdminFkName(admin.ModelAdmin):
    
  1216.             inlines = [InlineFkName, InlineNoFkName]
    
  1217. 
    
  1218.         self.assertIsValid(ProxyProxyChildAdminFkName, ProxyProxyChild)
    
  1219. 
    
  1220. 
    
  1221. class ExtraCheckTests(CheckTestCase):
    
  1222.     def test_not_integer(self):
    
  1223.         class ValidationTestInline(TabularInline):
    
  1224.             model = ValidationTestInlineModel
    
  1225.             extra = "hello"
    
  1226. 
    
  1227.         class TestModelAdmin(ModelAdmin):
    
  1228.             inlines = [ValidationTestInline]
    
  1229. 
    
  1230.         self.assertIsInvalid(
    
  1231.             TestModelAdmin,
    
  1232.             ValidationTestModel,
    
  1233.             "The value of 'extra' must be an integer.",
    
  1234.             "admin.E203",
    
  1235.             invalid_obj=ValidationTestInline,
    
  1236.         )
    
  1237. 
    
  1238.     def test_valid_case(self):
    
  1239.         class ValidationTestInline(TabularInline):
    
  1240.             model = ValidationTestInlineModel
    
  1241.             extra = 2
    
  1242. 
    
  1243.         class TestModelAdmin(ModelAdmin):
    
  1244.             inlines = [ValidationTestInline]
    
  1245. 
    
  1246.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1247. 
    
  1248. 
    
  1249. class MaxNumCheckTests(CheckTestCase):
    
  1250.     def test_not_integer(self):
    
  1251.         class ValidationTestInline(TabularInline):
    
  1252.             model = ValidationTestInlineModel
    
  1253.             max_num = "hello"
    
  1254. 
    
  1255.         class TestModelAdmin(ModelAdmin):
    
  1256.             inlines = [ValidationTestInline]
    
  1257. 
    
  1258.         self.assertIsInvalid(
    
  1259.             TestModelAdmin,
    
  1260.             ValidationTestModel,
    
  1261.             "The value of 'max_num' must be an integer.",
    
  1262.             "admin.E204",
    
  1263.             invalid_obj=ValidationTestInline,
    
  1264.         )
    
  1265. 
    
  1266.     def test_valid_case(self):
    
  1267.         class ValidationTestInline(TabularInline):
    
  1268.             model = ValidationTestInlineModel
    
  1269.             max_num = 2
    
  1270. 
    
  1271.         class TestModelAdmin(ModelAdmin):
    
  1272.             inlines = [ValidationTestInline]
    
  1273. 
    
  1274.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1275. 
    
  1276. 
    
  1277. class MinNumCheckTests(CheckTestCase):
    
  1278.     def test_not_integer(self):
    
  1279.         class ValidationTestInline(TabularInline):
    
  1280.             model = ValidationTestInlineModel
    
  1281.             min_num = "hello"
    
  1282. 
    
  1283.         class TestModelAdmin(ModelAdmin):
    
  1284.             inlines = [ValidationTestInline]
    
  1285. 
    
  1286.         self.assertIsInvalid(
    
  1287.             TestModelAdmin,
    
  1288.             ValidationTestModel,
    
  1289.             "The value of 'min_num' must be an integer.",
    
  1290.             "admin.E205",
    
  1291.             invalid_obj=ValidationTestInline,
    
  1292.         )
    
  1293. 
    
  1294.     def test_valid_case(self):
    
  1295.         class ValidationTestInline(TabularInline):
    
  1296.             model = ValidationTestInlineModel
    
  1297.             min_num = 2
    
  1298. 
    
  1299.         class TestModelAdmin(ModelAdmin):
    
  1300.             inlines = [ValidationTestInline]
    
  1301. 
    
  1302.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1303. 
    
  1304. 
    
  1305. class FormsetCheckTests(CheckTestCase):
    
  1306.     def test_invalid_type(self):
    
  1307.         class FakeFormSet:
    
  1308.             pass
    
  1309. 
    
  1310.         class ValidationTestInline(TabularInline):
    
  1311.             model = ValidationTestInlineModel
    
  1312.             formset = FakeFormSet
    
  1313. 
    
  1314.         class TestModelAdmin(ModelAdmin):
    
  1315.             inlines = [ValidationTestInline]
    
  1316. 
    
  1317.         self.assertIsInvalid(
    
  1318.             TestModelAdmin,
    
  1319.             ValidationTestModel,
    
  1320.             "The value of 'formset' must inherit from 'BaseModelFormSet'.",
    
  1321.             "admin.E206",
    
  1322.             invalid_obj=ValidationTestInline,
    
  1323.         )
    
  1324. 
    
  1325.     def test_inline_without_formset_class(self):
    
  1326.         class ValidationTestInlineWithoutFormsetClass(TabularInline):
    
  1327.             model = ValidationTestInlineModel
    
  1328.             formset = "Not a FormSet Class"
    
  1329. 
    
  1330.         class TestModelAdminWithoutFormsetClass(ModelAdmin):
    
  1331.             inlines = [ValidationTestInlineWithoutFormsetClass]
    
  1332. 
    
  1333.         self.assertIsInvalid(
    
  1334.             TestModelAdminWithoutFormsetClass,
    
  1335.             ValidationTestModel,
    
  1336.             "The value of 'formset' must inherit from 'BaseModelFormSet'.",
    
  1337.             "admin.E206",
    
  1338.             invalid_obj=ValidationTestInlineWithoutFormsetClass,
    
  1339.         )
    
  1340. 
    
  1341.     def test_valid_case(self):
    
  1342.         class RealModelFormSet(BaseModelFormSet):
    
  1343.             pass
    
  1344. 
    
  1345.         class ValidationTestInline(TabularInline):
    
  1346.             model = ValidationTestInlineModel
    
  1347.             formset = RealModelFormSet
    
  1348. 
    
  1349.         class TestModelAdmin(ModelAdmin):
    
  1350.             inlines = [ValidationTestInline]
    
  1351. 
    
  1352.         self.assertIsValid(TestModelAdmin, ValidationTestModel)
    
  1353. 
    
  1354. 
    
  1355. class ListDisplayEditableTests(CheckTestCase):
    
  1356.     def test_list_display_links_is_none(self):
    
  1357.         """
    
  1358.         list_display and list_editable can contain the same values
    
  1359.         when list_display_links is None
    
  1360.         """
    
  1361. 
    
  1362.         class ProductAdmin(ModelAdmin):
    
  1363.             list_display = ["name", "slug", "pub_date"]
    
  1364.             list_editable = list_display
    
  1365.             list_display_links = None
    
  1366. 
    
  1367.         self.assertIsValid(ProductAdmin, ValidationTestModel)
    
  1368. 
    
  1369.     def test_list_display_first_item_same_as_list_editable_first_item(self):
    
  1370.         """
    
  1371.         The first item in list_display can be the same as the first in
    
  1372.         list_editable.
    
  1373.         """
    
  1374. 
    
  1375.         class ProductAdmin(ModelAdmin):
    
  1376.             list_display = ["name", "slug", "pub_date"]
    
  1377.             list_editable = ["name", "slug"]
    
  1378.             list_display_links = ["pub_date"]
    
  1379. 
    
  1380.         self.assertIsValid(ProductAdmin, ValidationTestModel)
    
  1381. 
    
  1382.     def test_list_display_first_item_in_list_editable(self):
    
  1383.         """
    
  1384.         The first item in list_display can be in list_editable as long as
    
  1385.         list_display_links is defined.
    
  1386.         """
    
  1387. 
    
  1388.         class ProductAdmin(ModelAdmin):
    
  1389.             list_display = ["name", "slug", "pub_date"]
    
  1390.             list_editable = ["slug", "name"]
    
  1391.             list_display_links = ["pub_date"]
    
  1392. 
    
  1393.         self.assertIsValid(ProductAdmin, ValidationTestModel)
    
  1394. 
    
  1395.     def test_list_display_first_item_same_as_list_editable_no_list_display_links(self):
    
  1396.         """
    
  1397.         The first item in list_display cannot be the same as the first item
    
  1398.         in list_editable if list_display_links is not defined.
    
  1399.         """
    
  1400. 
    
  1401.         class ProductAdmin(ModelAdmin):
    
  1402.             list_display = ["name"]
    
  1403.             list_editable = ["name"]
    
  1404. 
    
  1405.         self.assertIsInvalid(
    
  1406.             ProductAdmin,
    
  1407.             ValidationTestModel,
    
  1408.             "The value of 'list_editable[0]' refers to the first field "
    
  1409.             "in 'list_display' ('name'), which cannot be used unless "
    
  1410.             "'list_display_links' is set.",
    
  1411.             id="admin.E124",
    
  1412.         )
    
  1413. 
    
  1414.     def test_list_display_first_item_in_list_editable_no_list_display_links(self):
    
  1415.         """
    
  1416.         The first item in list_display cannot be in list_editable if
    
  1417.         list_display_links isn't defined.
    
  1418.         """
    
  1419. 
    
  1420.         class ProductAdmin(ModelAdmin):
    
  1421.             list_display = ["name", "slug", "pub_date"]
    
  1422.             list_editable = ["slug", "name"]
    
  1423. 
    
  1424.         self.assertIsInvalid(
    
  1425.             ProductAdmin,
    
  1426.             ValidationTestModel,
    
  1427.             "The value of 'list_editable[1]' refers to the first field "
    
  1428.             "in 'list_display' ('name'), which cannot be used unless "
    
  1429.             "'list_display_links' is set.",
    
  1430.             id="admin.E124",
    
  1431.         )
    
  1432. 
    
  1433.     def test_both_list_editable_and_list_display_links(self):
    
  1434.         class ProductAdmin(ModelAdmin):
    
  1435.             list_editable = ("name",)
    
  1436.             list_display = ("name",)
    
  1437.             list_display_links = ("name",)
    
  1438. 
    
  1439.         self.assertIsInvalid(
    
  1440.             ProductAdmin,
    
  1441.             ValidationTestModel,
    
  1442.             "The value of 'name' cannot be in both 'list_editable' and "
    
  1443.             "'list_display_links'.",
    
  1444.             id="admin.E123",
    
  1445.         )
    
  1446. 
    
  1447. 
    
  1448. class AutocompleteFieldsTests(CheckTestCase):
    
  1449.     def test_autocomplete_e036(self):
    
  1450.         class Admin(ModelAdmin):
    
  1451.             autocomplete_fields = "name"
    
  1452. 
    
  1453.         self.assertIsInvalid(
    
  1454.             Admin,
    
  1455.             Band,
    
  1456.             msg="The value of 'autocomplete_fields' must be a list or tuple.",
    
  1457.             id="admin.E036",
    
  1458.             invalid_obj=Admin,
    
  1459.         )
    
  1460. 
    
  1461.     def test_autocomplete_e037(self):
    
  1462.         class Admin(ModelAdmin):
    
  1463.             autocomplete_fields = ("nonexistent",)
    
  1464. 
    
  1465.         self.assertIsInvalid(
    
  1466.             Admin,
    
  1467.             ValidationTestModel,
    
  1468.             msg=(
    
  1469.                 "The value of 'autocomplete_fields[0]' refers to 'nonexistent', "
    
  1470.                 "which is not a field of 'modeladmin.ValidationTestModel'."
    
  1471.             ),
    
  1472.             id="admin.E037",
    
  1473.             invalid_obj=Admin,
    
  1474.         )
    
  1475. 
    
  1476.     def test_autocomplete_e38(self):
    
  1477.         class Admin(ModelAdmin):
    
  1478.             autocomplete_fields = ("name",)
    
  1479. 
    
  1480.         self.assertIsInvalid(
    
  1481.             Admin,
    
  1482.             ValidationTestModel,
    
  1483.             msg=(
    
  1484.                 "The value of 'autocomplete_fields[0]' must be a foreign "
    
  1485.                 "key or a many-to-many field."
    
  1486.             ),
    
  1487.             id="admin.E038",
    
  1488.             invalid_obj=Admin,
    
  1489.         )
    
  1490. 
    
  1491.     def test_autocomplete_e039(self):
    
  1492.         class Admin(ModelAdmin):
    
  1493.             autocomplete_fields = ("band",)
    
  1494. 
    
  1495.         self.assertIsInvalid(
    
  1496.             Admin,
    
  1497.             Song,
    
  1498.             msg=(
    
  1499.                 'An admin for model "Band" has to be registered '
    
  1500.                 "to be referenced by Admin.autocomplete_fields."
    
  1501.             ),
    
  1502.             id="admin.E039",
    
  1503.             invalid_obj=Admin,
    
  1504.         )
    
  1505. 
    
  1506.     def test_autocomplete_e040(self):
    
  1507.         class NoSearchFieldsAdmin(ModelAdmin):
    
  1508.             pass
    
  1509. 
    
  1510.         class AutocompleteAdmin(ModelAdmin):
    
  1511.             autocomplete_fields = ("featuring",)
    
  1512. 
    
  1513.         site = AdminSite()
    
  1514.         site.register(Band, NoSearchFieldsAdmin)
    
  1515.         self.assertIsInvalid(
    
  1516.             AutocompleteAdmin,
    
  1517.             Song,
    
  1518.             msg=(
    
  1519.                 'NoSearchFieldsAdmin must define "search_fields", because '
    
  1520.                 "it's referenced by AutocompleteAdmin.autocomplete_fields."
    
  1521.             ),
    
  1522.             id="admin.E040",
    
  1523.             invalid_obj=AutocompleteAdmin,
    
  1524.             admin_site=site,
    
  1525.         )
    
  1526. 
    
  1527.     def test_autocomplete_is_valid(self):
    
  1528.         class SearchFieldsAdmin(ModelAdmin):
    
  1529.             search_fields = "name"
    
  1530. 
    
  1531.         class AutocompleteAdmin(ModelAdmin):
    
  1532.             autocomplete_fields = ("featuring",)
    
  1533. 
    
  1534.         site = AdminSite()
    
  1535.         site.register(Band, SearchFieldsAdmin)
    
  1536.         self.assertIsValid(AutocompleteAdmin, Song, admin_site=site)
    
  1537. 
    
  1538.     def test_autocomplete_is_onetoone(self):
    
  1539.         class UserAdmin(ModelAdmin):
    
  1540.             search_fields = ("name",)
    
  1541. 
    
  1542.         class Admin(ModelAdmin):
    
  1543.             autocomplete_fields = ("best_friend",)
    
  1544. 
    
  1545.         site = AdminSite()
    
  1546.         site.register(User, UserAdmin)
    
  1547.         self.assertIsValid(Admin, ValidationTestModel, admin_site=site)
    
  1548. 
    
  1549. 
    
  1550. class ActionsCheckTests(CheckTestCase):
    
  1551.     def test_custom_permissions_require_matching_has_method(self):
    
  1552.         @admin.action(permissions=["custom"])
    
  1553.         def custom_permission_action(modeladmin, request, queryset):
    
  1554.             pass
    
  1555. 
    
  1556.         class BandAdmin(ModelAdmin):
    
  1557.             actions = (custom_permission_action,)
    
  1558. 
    
  1559.         self.assertIsInvalid(
    
  1560.             BandAdmin,
    
  1561.             Band,
    
  1562.             "BandAdmin must define a has_custom_permission() method for the "
    
  1563.             "custom_permission_action action.",
    
  1564.             id="admin.E129",
    
  1565.         )
    
  1566. 
    
  1567.     def test_actions_not_unique(self):
    
  1568.         @admin.action
    
  1569.         def action(modeladmin, request, queryset):
    
  1570.             pass
    
  1571. 
    
  1572.         class BandAdmin(ModelAdmin):
    
  1573.             actions = (action, action)
    
  1574. 
    
  1575.         self.assertIsInvalid(
    
  1576.             BandAdmin,
    
  1577.             Band,
    
  1578.             "__name__ attributes of actions defined in BandAdmin must be "
    
  1579.             "unique. Name 'action' is not unique.",
    
  1580.             id="admin.E130",
    
  1581.         )
    
  1582. 
    
  1583.     def test_actions_unique(self):
    
  1584.         @admin.action
    
  1585.         def action1(modeladmin, request, queryset):
    
  1586.             pass
    
  1587. 
    
  1588.         @admin.action
    
  1589.         def action2(modeladmin, request, queryset):
    
  1590.             pass
    
  1591. 
    
  1592.         class BandAdmin(ModelAdmin):
    
  1593.             actions = (action1, action2)
    
  1594. 
    
  1595.         self.assertIsValid(BandAdmin, Band)