/tests/regressiontests/admin_validation/tests.py

https://code.google.com/p/mango-py/ · Python · 253 lines · 233 code · 11 blank · 9 comment · 2 complexity · 655746680b41ef2809835af44e4f6cef MD5 · raw file

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