Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.2.X] Migrated admin_validation doctests. Thanks to Sebastian Hillig.

Backport of r13883 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@13904 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e8ccba765cd9c2db624dcaf7fcc2cf638193f517 1 parent d99f19f
Russell Keith-Magee authored September 27, 2010
217  tests/regressiontests/admin_validation/models.py
@@ -45,220 +45,3 @@ class Book(models.Model):
45 45
 class AuthorsBooks(models.Model):
46 46
     author = models.ForeignKey(Author)
47 47
     book = models.ForeignKey(Book)
48  
-
49  
-
50  
-__test__ = {'API_TESTS':"""
51  
-
52  
->>> from django import forms
53  
->>> from django.contrib import admin
54  
->>> from django.contrib.admin.validation import validate, validate_inline
55  
-
56  
-# Regression test for #8027: custom ModelForms with fields/fieldsets
57  
-
58  
->>> class SongForm(forms.ModelForm):
59  
-...     pass
60  
-
61  
->>> class ValidFields(admin.ModelAdmin):
62  
-...     form = SongForm
63  
-...     fields = ['title']
64  
-
65  
->>> class InvalidFields(admin.ModelAdmin):
66  
-...     form = SongForm
67  
-...     fields = ['spam']
68  
-
69  
->>> validate(ValidFields, Song)
70  
->>> validate(InvalidFields, Song)
71  
-Traceback (most recent call last):
72  
-    ...
73  
-ImproperlyConfigured: 'InvalidFields.fields' refers to field 'spam' that is missing from the form.
74  
-
75  
-# Tests for basic validation of 'exclude' option values (#12689)
76  
-
77  
->>> class ExcludedFields1(admin.ModelAdmin):
78  
-...     exclude = ('foo')
79  
-
80  
->>> validate(ExcludedFields1, Book)
81  
-Traceback (most recent call last):
82  
-    ...
83  
-ImproperlyConfigured: 'ExcludedFields1.exclude' must be a list or tuple.
84  
-
85  
->>> class ExcludedFields2(admin.ModelAdmin):
86  
-...     exclude = ('name', 'name')
87  
-
88  
->>> validate(ExcludedFields2, Book)
89  
-Traceback (most recent call last):
90  
-    ...
91  
-ImproperlyConfigured: There are duplicate field(s) in ExcludedFields2.exclude
92  
-
93  
->>> class ExcludedFieldsInline(admin.TabularInline):
94  
-...     model = Song
95  
-...     exclude = ('foo')
96  
-
97  
->>> class ExcludedFieldsAlbumAdmin(admin.ModelAdmin):
98  
-...     model = Album
99  
-...     inlines = [ExcludedFieldsInline]
100  
-
101  
->>> validate(ExcludedFieldsAlbumAdmin, Album)
102  
-Traceback (most recent call last):
103  
-    ...
104  
-ImproperlyConfigured: 'ExcludedFieldsInline.exclude' must be a list or tuple.
105  
-
106  
-# Regression test for #9932 - exclude in InlineModelAdmin
107  
-# should not contain the ForeignKey field used in ModelAdmin.model
108  
-
109  
->>> class SongInline(admin.StackedInline):
110  
-...     model = Song
111  
-...     exclude = ['album']
112  
-
113  
->>> class AlbumAdmin(admin.ModelAdmin):
114  
-...     model = Album
115  
-...     inlines = [SongInline]
116  
-
117  
->>> validate(AlbumAdmin, Album)
118  
-Traceback (most recent call last):
119  
-    ...
120  
-ImproperlyConfigured: SongInline cannot exclude the field 'album' - this is the foreign key to the parent model Album.
121  
-
122  
-# Regression test for #11709 - when testing for fk excluding (when exclude is
123  
-# given) make sure fk_name is honored or things blow up when there is more
124  
-# than one fk to the parent model.
125  
-
126  
->>> class TwoAlbumFKAndAnEInline(admin.TabularInline):
127  
-...     model = TwoAlbumFKAndAnE
128  
-...     exclude = ("e",)
129  
-...     fk_name = "album1"
130  
-
131  
->>> validate_inline(TwoAlbumFKAndAnEInline, None, Album)
132  
-
133  
-# Ensure inlines validate that they can be used correctly.
134  
-
135  
->>> class TwoAlbumFKAndAnEInline(admin.TabularInline):
136  
-...     model = TwoAlbumFKAndAnE
137  
-
138  
->>> validate_inline(TwoAlbumFKAndAnEInline, None, Album)
139  
-Traceback (most recent call last):
140  
-    ...
141  
-Exception: <class 'regressiontests.admin_validation.models.TwoAlbumFKAndAnE'> has more than 1 ForeignKey to <class 'regressiontests.admin_validation.models.Album'>
142  
-
143  
->>> class TwoAlbumFKAndAnEInline(admin.TabularInline):
144  
-...     model = TwoAlbumFKAndAnE
145  
-...     fk_name = "album1"
146  
-
147  
->>> validate_inline(TwoAlbumFKAndAnEInline, None, Album)
148  
-
149  
->>> class SongAdmin(admin.ModelAdmin):
150  
-...     readonly_fields = ("title",)
151  
-
152  
->>> validate(SongAdmin, Song)
153  
-
154  
->>> def my_function(obj):
155  
-...     # does nothing
156  
-...     pass
157  
->>> class SongAdmin(admin.ModelAdmin):
158  
-...     readonly_fields = (my_function,)
159  
-
160  
->>> validate(SongAdmin, Song)
161  
-
162  
->>> class SongAdmin(admin.ModelAdmin):
163  
-...     readonly_fields = ("readonly_method_on_modeladmin",)
164  
-...
165  
-...     def readonly_method_on_modeladmin(self, obj):
166  
-...         # does nothing
167  
-...         pass
168  
-
169  
->>> validate(SongAdmin, Song)
170  
-
171  
->>> class SongAdmin(admin.ModelAdmin):
172  
-...     readonly_fields = ("readonly_method_on_model",)
173  
-
174  
->>> validate(SongAdmin, Song)
175  
-
176  
->>> class SongAdmin(admin.ModelAdmin):
177  
-...     readonly_fields = ("title", "nonexistant")
178  
-
179  
->>> validate(SongAdmin, Song)
180  
-Traceback (most recent call last):
181  
-    ...
182  
-ImproperlyConfigured: SongAdmin.readonly_fields[1], 'nonexistant' is not a callable or an attribute of 'SongAdmin' or found in the model 'Song'.
183  
-
184  
->>> class SongAdmin(admin.ModelAdmin):
185  
-...     readonly_fields = ("title", "awesome_song")
186  
-...     fields = ("album", "title", "awesome_song")
187  
-
188  
->>> validate(SongAdmin, Song)
189  
-Traceback (most recent call last):
190  
-    ...
191  
-ImproperlyConfigured: SongAdmin.readonly_fields[1], 'awesome_song' is not a callable or an attribute of 'SongAdmin' or found in the model 'Song'.
192  
-
193  
->>> class SongAdmin(SongAdmin):
194  
-...     def awesome_song(self, instance):
195  
-...         if instance.title == "Born to Run":
196  
-...             return "Best Ever!"
197  
-...         return "Status unknown."
198  
-
199  
->>> validate(SongAdmin, Song)
200  
-
201  
->>> class SongAdmin(admin.ModelAdmin):
202  
-...     readonly_fields = (lambda obj: "test",)
203  
-
204  
->>> validate(SongAdmin, Song)
205  
-
206  
-# Regression test for #12203/#12237 - Fail more gracefully when a M2M field that
207  
-# specifies the 'through' option is included in the 'fields' or the 'fieldsets'
208  
-# ModelAdmin options.
209  
-
210  
->>> class BookAdmin(admin.ModelAdmin):
211  
-...     fields = ['authors']
212  
-
213  
->>> validate(BookAdmin, Book)
214  
-Traceback (most recent call last):
215  
-    ...
216  
-ImproperlyConfigured: 'BookAdmin.fields' can't include the ManyToManyField field 'authors' because 'authors' manually specifies a 'through' model.
217  
-
218  
->>> class FieldsetBookAdmin(admin.ModelAdmin):
219  
-...     fieldsets = (
220  
-...         ('Header 1', {'fields': ('name',)}),
221  
-...         ('Header 2', {'fields': ('authors',)}),
222  
-...     )
223  
-
224  
->>> validate(FieldsetBookAdmin, Book)
225  
-Traceback (most recent call last):
226  
-   ...
227  
-ImproperlyConfigured: 'FieldsetBookAdmin.fieldsets[1][1]['fields']' can't include the ManyToManyField field 'authors' because 'authors' manually specifies a 'through' model.
228  
-
229  
->>> class NestedFieldsetAdmin(admin.ModelAdmin):
230  
-...    fieldsets = (
231  
-...        ('Main', {'fields': ('price', ('name', 'subtitle'))}),
232  
-...    )
233  
-
234  
->>> validate(NestedFieldsetAdmin, Book)
235  
-
236  
-# Regression test for #12209 -- If the explicitly provided through model
237  
-# is specified as a string, the admin should still be able use
238  
-# Model.m2m_field.through
239  
-
240  
->>> class AuthorsInline(admin.TabularInline):
241  
-...     model = Book.authors.through
242  
-
243  
->>> class BookAdmin(admin.ModelAdmin):
244  
-...     inlines = [AuthorsInline]
245  
-
246  
-# If the through model is still a string (and hasn't been resolved to a model)
247  
-# the validation will fail.
248  
->>> validate(BookAdmin, Book)
249  
-
250  
-# Regression for ensuring ModelAdmin.fields can contain non-model fields
251  
-# that broke with r11737
252  
-
253  
->>> class SongForm(forms.ModelForm):
254  
-...     extra_data = forms.CharField()
255  
-...     class Meta:
256  
-...         model = Song
257  
-
258  
->>> class FieldsOnFormOnlyAdmin(admin.ModelAdmin):
259  
-...     form = SongForm
260  
-...     fields = ['title', 'extra_data']
261  
-
262  
->>> validate(FieldsOnFormOnlyAdmin, Song)
263  
-
264  
-"""}
235  tests/regressiontests/admin_validation/tests.py
... ...
@@ -1,11 +1,30 @@
1 1
 from django.contrib import admin
2  
-from django.contrib.admin.validation import validate
  2
+from django import forms
  3
+from django.contrib.admin.validation import validate, validate_inline, \
  4
+                                            ImproperlyConfigured
3 5
 from django.test import TestCase
4 6
 
5  
-from models import Song
  7
+from models import Song, Book, Album, TwoAlbumFKAndAnE
6 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']
7 19
 
8 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
+
9 28
     def test_readonly_and_editable(self):
10 29
         class SongAdmin(admin.ModelAdmin):
11 30
             readonly_fields = ["original_release"]
@@ -14,5 +33,215 @@ class SongAdmin(admin.ModelAdmin):
14 33
                     "fields": ["title", "original_release"],
15 34
                 }),
16 35
             ]
17  
-        
18 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
+

0 notes on commit e8ccba7

Please sign in to comment.
Something went wrong with that request. Please try again.