parts/django/tests/regressiontests/admin_validation/tests.py
changeset 307 c6bca38c1cbf
equal deleted inserted replaced
306:5ff1fc726848 307:c6bca38c1cbf
       
     1 from django.contrib import admin
       
     2 from django import forms
       
     3 from django.contrib.admin.validation import validate, validate_inline, \
       
     4                                             ImproperlyConfigured
       
     5 from django.test import TestCase
       
     6 
       
     7 from models import Song, Book, Album, TwoAlbumFKAndAnE
       
     8 
       
     9 class SongForm(forms.ModelForm):
       
    10     pass
       
    11 
       
    12 class ValidFields(admin.ModelAdmin):
       
    13     form = SongForm
       
    14     fields = ['title']
       
    15 
       
    16 class InvalidFields(admin.ModelAdmin):
       
    17     form = SongForm
       
    18     fields = ['spam']
       
    19 
       
    20 class ValidationTestCase(TestCase):
       
    21     def assertRaisesMessage(self, exc, msg, func, *args, **kwargs):
       
    22         try:
       
    23             func(*args, **kwargs)
       
    24         except Exception, e:
       
    25             self.assertEqual(msg, str(e))
       
    26             self.assertTrue(isinstance(e, exc), "Expected %s, got %s" % (exc, type(e)))
       
    27 
       
    28     def test_readonly_and_editable(self):
       
    29         class SongAdmin(admin.ModelAdmin):
       
    30             readonly_fields = ["original_release"]
       
    31             fieldsets = [
       
    32                 (None, {
       
    33                     "fields": ["title", "original_release"],
       
    34                 }),
       
    35             ]
       
    36         validate(SongAdmin, Song)
       
    37 
       
    38     def test_custom_modelforms_with_fields_fieldsets(self):
       
    39         """
       
    40         # Regression test for #8027: custom ModelForms with fields/fieldsets
       
    41         """
       
    42         validate(ValidFields, Song)
       
    43         self.assertRaisesMessage(ImproperlyConfigured,
       
    44             "'InvalidFields.fields' refers to field 'spam' that is missing from the form.",
       
    45             validate,
       
    46             InvalidFields, Song)
       
    47 
       
    48     def test_exclude_values(self):
       
    49         """
       
    50         Tests for basic validation of 'exclude' option values (#12689)
       
    51         """
       
    52         class ExcludedFields1(admin.ModelAdmin):
       
    53             exclude = ('foo')
       
    54         self.assertRaisesMessage(ImproperlyConfigured,
       
    55             "'ExcludedFields1.exclude' must be a list or tuple.",
       
    56             validate,
       
    57             ExcludedFields1, Book)
       
    58 
       
    59     def test_exclude_duplicate_values(self):
       
    60         class ExcludedFields2(admin.ModelAdmin):
       
    61             exclude = ('name', 'name')
       
    62         self.assertRaisesMessage(ImproperlyConfigured,
       
    63             "There are duplicate field(s) in ExcludedFields2.exclude",
       
    64             validate,
       
    65             ExcludedFields2, Book)
       
    66 
       
    67     def test_exclude_in_inline(self):
       
    68         class ExcludedFieldsInline(admin.TabularInline):
       
    69             model = Song
       
    70             exclude = ('foo')
       
    71 
       
    72         class ExcludedFieldsAlbumAdmin(admin.ModelAdmin):
       
    73             model = Album
       
    74             inlines = [ExcludedFieldsInline]
       
    75 
       
    76         self.assertRaisesMessage(ImproperlyConfigured,
       
    77             "'ExcludedFieldsInline.exclude' must be a list or tuple.",
       
    78             validate,
       
    79             ExcludedFieldsAlbumAdmin, Album)
       
    80 
       
    81     def test_exclude_inline_model_admin(self):
       
    82         """
       
    83         # Regression test for #9932 - exclude in InlineModelAdmin
       
    84         # should not contain the ForeignKey field used in ModelAdmin.model
       
    85         """
       
    86         class SongInline(admin.StackedInline):
       
    87             model = Song
       
    88             exclude = ['album']
       
    89 
       
    90         class AlbumAdmin(admin.ModelAdmin):
       
    91             model = Album
       
    92             inlines = [SongInline]
       
    93 
       
    94         self.assertRaisesMessage(ImproperlyConfigured,
       
    95             "SongInline cannot exclude the field 'album' - this is the foreign key to the parent model Album.",
       
    96             validate,
       
    97             AlbumAdmin, Album)
       
    98 
       
    99     def test_fk_exclusion(self):
       
   100         """
       
   101         Regression test for #11709 - when testing for fk excluding (when exclude is
       
   102         given) make sure fk_name is honored or things blow up when there is more
       
   103         than one fk to the parent model.
       
   104         """
       
   105         class TwoAlbumFKAndAnEInline(admin.TabularInline):
       
   106             model = TwoAlbumFKAndAnE
       
   107             exclude = ("e",)
       
   108             fk_name = "album1"
       
   109         validate_inline(TwoAlbumFKAndAnEInline, None, Album)
       
   110 
       
   111     def test_inline_self_validation(self):
       
   112         class TwoAlbumFKAndAnEInline(admin.TabularInline):
       
   113             model = TwoAlbumFKAndAnE
       
   114 
       
   115         self.assertRaisesMessage(Exception,
       
   116             "<class 'regressiontests.admin_validation.models.TwoAlbumFKAndAnE'> has more than 1 ForeignKey to <class 'regressiontests.admin_validation.models.Album'>",
       
   117             validate_inline,
       
   118             TwoAlbumFKAndAnEInline, None, Album)
       
   119 
       
   120     def test_inline_with_specified(self):
       
   121         class TwoAlbumFKAndAnEInline(admin.TabularInline):
       
   122             model = TwoAlbumFKAndAnE
       
   123             fk_name = "album1"
       
   124         validate_inline(TwoAlbumFKAndAnEInline, None, Album)
       
   125 
       
   126     def test_readonly(self):
       
   127         class SongAdmin(admin.ModelAdmin):
       
   128             readonly_fields = ("title",)
       
   129 
       
   130         validate(SongAdmin, Song)
       
   131 
       
   132     def test_readonly_on_method(self):
       
   133         def my_function(obj):
       
   134             pass
       
   135 
       
   136         class SongAdmin(admin.ModelAdmin):
       
   137             readonly_fields = (my_function,)
       
   138 
       
   139         validate(SongAdmin, Song)
       
   140 
       
   141     def test_readonly_on_modeladmin(self):
       
   142         class SongAdmin(admin.ModelAdmin):
       
   143             readonly_fields = ("readonly_method_on_modeladmin",)
       
   144 
       
   145             def readonly_method_on_modeladmin(self, obj):
       
   146                 pass
       
   147 
       
   148         validate(SongAdmin, Song)
       
   149 
       
   150     def test_readonly_method_on_model(self):
       
   151         class SongAdmin(admin.ModelAdmin):
       
   152             readonly_fields = ("readonly_method_on_model",)
       
   153 
       
   154         validate(SongAdmin, Song)
       
   155 
       
   156     def test_nonexistant_field(self):
       
   157         class SongAdmin(admin.ModelAdmin):
       
   158             readonly_fields = ("title", "nonexistant")
       
   159 
       
   160         self.assertRaisesMessage(ImproperlyConfigured,
       
   161             "SongAdmin.readonly_fields[1], 'nonexistant' is not a callable or an attribute of 'SongAdmin' or found in the model 'Song'.",
       
   162             validate,
       
   163             SongAdmin, Song)
       
   164 
       
   165     def test_extra(self):
       
   166         class SongAdmin(admin.ModelAdmin):
       
   167             def awesome_song(self, instance):
       
   168                 if instance.title == "Born to Run":
       
   169                     return "Best Ever!"
       
   170                 return "Status unknown."
       
   171         validate(SongAdmin, Song)
       
   172 
       
   173     def test_readonly_lambda(self):
       
   174         class SongAdmin(admin.ModelAdmin):
       
   175             readonly_fields = (lambda obj: "test",)
       
   176 
       
   177         validate(SongAdmin, Song)
       
   178 
       
   179     def test_graceful_m2m_fail(self):
       
   180         """
       
   181         Regression test for #12203/#12237 - Fail more gracefully when a M2M field that
       
   182         specifies the 'through' option is included in the 'fields' or the 'fieldsets'
       
   183         ModelAdmin options.
       
   184         """
       
   185 
       
   186         class BookAdmin(admin.ModelAdmin):
       
   187             fields = ['authors']
       
   188 
       
   189         self.assertRaisesMessage(ImproperlyConfigured,
       
   190             "'BookAdmin.fields' can't include the ManyToManyField field 'authors' because 'authors' manually specifies a 'through' model.",
       
   191             validate,
       
   192             BookAdmin, Book)
       
   193 
       
   194     def test_cannon_include_through(self):
       
   195         class FieldsetBookAdmin(admin.ModelAdmin):
       
   196             fieldsets = (
       
   197                 ('Header 1', {'fields': ('name',)}),
       
   198                 ('Header 2', {'fields': ('authors',)}),
       
   199             )
       
   200         self.assertRaisesMessage(ImproperlyConfigured,
       
   201             "'FieldsetBookAdmin.fieldsets[1][1]['fields']' can't include the ManyToManyField field 'authors' because 'authors' manually specifies a 'through' model.",
       
   202             validate,
       
   203             FieldsetBookAdmin, Book)
       
   204 
       
   205     def test_nested_fieldsets(self):
       
   206         class NestedFieldsetAdmin(admin.ModelAdmin):
       
   207            fieldsets = (
       
   208                ('Main', {'fields': ('price', ('name', 'subtitle'))}),
       
   209            )
       
   210         validate(NestedFieldsetAdmin, Book)
       
   211 
       
   212     def test_explicit_through_override(self):
       
   213         """
       
   214         Regression test for #12209 -- If the explicitly provided through model
       
   215         is specified as a string, the admin should still be able use
       
   216         Model.m2m_field.through
       
   217         """
       
   218 
       
   219         class AuthorsInline(admin.TabularInline):
       
   220             model = Book.authors.through
       
   221 
       
   222         class BookAdmin(admin.ModelAdmin):
       
   223             inlines = [AuthorsInline]
       
   224 
       
   225         # If the through model is still a string (and hasn't been resolved to a model)
       
   226         # the validation will fail.
       
   227         validate(BookAdmin, Book)
       
   228 
       
   229     def test_non_model_fields(self):
       
   230         """
       
   231         Regression for ensuring ModelAdmin.fields can contain non-model fields
       
   232         that broke with r11737
       
   233         """
       
   234         class SongForm(forms.ModelForm):
       
   235             extra_data = forms.CharField()
       
   236             class Meta:
       
   237                 model = Song
       
   238 
       
   239         class FieldsOnFormOnlyAdmin(admin.ModelAdmin):
       
   240             form = SongForm
       
   241             fields = ['title', 'extra_data']
       
   242 
       
   243         validate(FieldsOnFormOnlyAdmin, Song)
       
   244 
       
   245 
       
   246 
       
   247