2010-03-09 04:36:37 +08:00
from django . contrib import admin
2010-09-27 23:12:22 +08:00
from django import forms
from django . contrib . admin . validation import validate , validate_inline , \
ImproperlyConfigured
2010-03-09 04:36:37 +08:00
from django . test import TestCase
2011-02-26 09:44:41 +08:00
from models import Song , Book , Album , TwoAlbumFKAndAnE , State , City
2010-03-09 04:36:37 +08:00
2010-09-27 23:12:22 +08:00
class SongForm ( forms . ModelForm ) :
pass
class ValidFields ( admin . ModelAdmin ) :
form = SongForm
fields = [ ' title ' ]
class InvalidFields ( admin . ModelAdmin ) :
form = SongForm
fields = [ ' spam ' ]
2010-03-09 04:36:37 +08:00
class ValidationTestCase ( TestCase ) :
2010-09-27 23:12:22 +08:00
def assertRaisesMessage ( self , exc , msg , func , * args , * * kwargs ) :
try :
func ( * args , * * kwargs )
except Exception , e :
self . assertEqual ( msg , str ( e ) )
self . assertTrue ( isinstance ( e , exc ) , " Expected %s , got %s " % ( exc , type ( e ) ) )
2010-03-09 04:36:37 +08:00
def test_readonly_and_editable ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = [ " original_release " ]
fieldsets = [
( None , {
" fields " : [ " title " , " original_release " ] ,
} ) ,
]
validate ( SongAdmin , Song )
2010-09-27 23:12:22 +08:00
def test_custom_modelforms_with_fields_fieldsets ( self ) :
"""
# Regression test for #8027: custom ModelForms with fields/fieldsets
"""
validate ( ValidFields , Song )
self . assertRaisesMessage ( ImproperlyConfigured ,
" ' InvalidFields.fields ' refers to field ' spam ' that is missing from the form. " ,
validate ,
InvalidFields , Song )
def test_exclude_values ( self ) :
"""
Tests for basic validation of ' exclude ' option values ( #12689)
"""
class ExcludedFields1 ( admin . ModelAdmin ) :
exclude = ( ' foo ' )
self . assertRaisesMessage ( ImproperlyConfigured ,
" ' ExcludedFields1.exclude ' must be a list or tuple. " ,
validate ,
ExcludedFields1 , Book )
def test_exclude_duplicate_values ( self ) :
class ExcludedFields2 ( admin . ModelAdmin ) :
exclude = ( ' name ' , ' name ' )
self . assertRaisesMessage ( ImproperlyConfigured ,
" There are duplicate field(s) in ExcludedFields2.exclude " ,
validate ,
ExcludedFields2 , Book )
def test_exclude_in_inline ( self ) :
class ExcludedFieldsInline ( admin . TabularInline ) :
model = Song
exclude = ( ' foo ' )
class ExcludedFieldsAlbumAdmin ( admin . ModelAdmin ) :
model = Album
inlines = [ ExcludedFieldsInline ]
self . assertRaisesMessage ( ImproperlyConfigured ,
" ' ExcludedFieldsInline.exclude ' must be a list or tuple. " ,
validate ,
ExcludedFieldsAlbumAdmin , Album )
def test_exclude_inline_model_admin ( self ) :
"""
# Regression test for #9932 - exclude in InlineModelAdmin
# should not contain the ForeignKey field used in ModelAdmin.model
"""
class SongInline ( admin . StackedInline ) :
model = Song
exclude = [ ' album ' ]
class AlbumAdmin ( admin . ModelAdmin ) :
model = Album
inlines = [ SongInline ]
self . assertRaisesMessage ( ImproperlyConfigured ,
2011-06-27 00:52:31 +08:00
" SongInline cannot exclude the field ' album ' - this is the foreign key to the parent model admin_validation.Album. " ,
2010-09-27 23:12:22 +08:00
validate ,
AlbumAdmin , Album )
2011-06-27 00:52:31 +08:00
def test_app_label_in_admin_validation ( self ) :
"""
Regression test for #15669 - Include app label in admin validation messages
"""
class RawIdNonexistingAdmin ( admin . ModelAdmin ) :
raw_id_fields = ( ' nonexisting ' , )
self . assertRaisesMessage ( ImproperlyConfigured ,
" ' RawIdNonexistingAdmin.raw_id_fields ' refers to field ' nonexisting ' that is missing from model ' admin_validation.Album ' . " ,
validate ,
RawIdNonexistingAdmin , Album )
2010-09-27 23:12:22 +08:00
def test_fk_exclusion ( self ) :
"""
Regression test for #11709 - when testing for fk excluding (when exclude is
given ) make sure fk_name is honored or things blow up when there is more
than one fk to the parent model .
"""
class TwoAlbumFKAndAnEInline ( admin . TabularInline ) :
model = TwoAlbumFKAndAnE
exclude = ( " e " , )
fk_name = " album1 "
validate_inline ( TwoAlbumFKAndAnEInline , None , Album )
def test_inline_self_validation ( self ) :
class TwoAlbumFKAndAnEInline ( admin . TabularInline ) :
model = TwoAlbumFKAndAnE
self . assertRaisesMessage ( Exception ,
" <class ' regressiontests.admin_validation.models.TwoAlbumFKAndAnE ' > has more than 1 ForeignKey to <class ' regressiontests.admin_validation.models.Album ' > " ,
validate_inline ,
TwoAlbumFKAndAnEInline , None , Album )
def test_inline_with_specified ( self ) :
class TwoAlbumFKAndAnEInline ( admin . TabularInline ) :
model = TwoAlbumFKAndAnE
fk_name = " album1 "
validate_inline ( TwoAlbumFKAndAnEInline , None , Album )
def test_readonly ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = ( " title " , )
validate ( SongAdmin , Song )
def test_readonly_on_method ( self ) :
def my_function ( obj ) :
pass
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = ( my_function , )
validate ( SongAdmin , Song )
def test_readonly_on_modeladmin ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = ( " readonly_method_on_modeladmin " , )
def readonly_method_on_modeladmin ( self , obj ) :
pass
validate ( SongAdmin , Song )
def test_readonly_method_on_model ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = ( " readonly_method_on_model " , )
validate ( SongAdmin , Song )
def test_nonexistant_field ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = ( " title " , " nonexistant " )
self . assertRaisesMessage ( ImproperlyConfigured ,
" SongAdmin.readonly_fields[1], ' nonexistant ' is not a callable or an attribute of ' SongAdmin ' or found in the model ' Song ' . " ,
validate ,
SongAdmin , Song )
2011-02-26 09:44:41 +08:00
def test_nonexistant_field_on_inline ( self ) :
class CityInline ( admin . TabularInline ) :
model = City
readonly_fields = [ ' i_dont_exist ' ] # Missing attribute
self . assertRaisesMessage ( ImproperlyConfigured ,
" CityInline.readonly_fields[0], ' i_dont_exist ' is not a callable or an attribute of ' CityInline ' or found in the model ' City ' . " ,
validate_inline ,
CityInline , None , State )
2010-09-27 23:12:22 +08:00
def test_extra ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
def awesome_song ( self , instance ) :
if instance . title == " Born to Run " :
return " Best Ever! "
return " Status unknown. "
validate ( SongAdmin , Song )
def test_readonly_lambda ( self ) :
class SongAdmin ( admin . ModelAdmin ) :
readonly_fields = ( lambda obj : " test " , )
validate ( SongAdmin , Song )
def test_graceful_m2m_fail ( self ) :
"""
Regression test for #12203/#12237 - Fail more gracefully when a M2M field that
specifies the ' through ' option is included in the ' fields ' or the ' fieldsets '
ModelAdmin options .
"""
class BookAdmin ( admin . ModelAdmin ) :
fields = [ ' authors ' ]
self . assertRaisesMessage ( ImproperlyConfigured ,
" ' BookAdmin.fields ' can ' t include the ManyToManyField field ' authors ' because ' authors ' manually specifies a ' through ' model. " ,
validate ,
BookAdmin , Book )
2011-05-15 00:29:39 +08:00
def test_cannot_include_through ( self ) :
2010-09-27 23:12:22 +08:00
class FieldsetBookAdmin ( admin . ModelAdmin ) :
fieldsets = (
( ' Header 1 ' , { ' fields ' : ( ' name ' , ) } ) ,
( ' Header 2 ' , { ' fields ' : ( ' authors ' , ) } ) ,
)
self . assertRaisesMessage ( ImproperlyConfigured ,
" ' FieldsetBookAdmin.fieldsets[1][1][ ' fields ' ] ' can ' t include the ManyToManyField field ' authors ' because ' authors ' manually specifies a ' through ' model. " ,
validate ,
FieldsetBookAdmin , Book )
2011-05-15 00:29:39 +08:00
def test_nested_fields ( self ) :
class NestedFieldsAdmin ( admin . ModelAdmin ) :
fields = ( ' price ' , ( ' name ' , ' subtitle ' ) )
validate ( NestedFieldsAdmin , Book )
2010-09-27 23:12:22 +08:00
def test_nested_fieldsets ( self ) :
class NestedFieldsetAdmin ( admin . ModelAdmin ) :
fieldsets = (
( ' Main ' , { ' fields ' : ( ' price ' , ( ' name ' , ' subtitle ' ) ) } ) ,
)
validate ( NestedFieldsetAdmin , Book )
def test_explicit_through_override ( self ) :
"""
Regression test for #12209 -- If the explicitly provided through model
is specified as a string , the admin should still be able use
Model . m2m_field . through
"""
class AuthorsInline ( admin . TabularInline ) :
model = Book . authors . through
class BookAdmin ( admin . ModelAdmin ) :
inlines = [ AuthorsInline ]
# If the through model is still a string (and hasn't been resolved to a model)
# the validation will fail.
validate ( BookAdmin , Book )
def test_non_model_fields ( self ) :
"""
Regression for ensuring ModelAdmin . fields can contain non - model fields
that broke with r11737
"""
class SongForm ( forms . ModelForm ) :
extra_data = forms . CharField ( )
class Meta :
model = Song
class FieldsOnFormOnlyAdmin ( admin . ModelAdmin ) :
form = SongForm
fields = [ ' title ' , ' extra_data ' ]
validate ( FieldsOnFormOnlyAdmin , Song )
2011-05-22 23:51:22 +08:00
def test_non_model_first_field ( self ) :
"""
Regression for ensuring ModelAdmin . field can handle first elem being a
non - model field ( test fix for UnboundLocalError introduced with r16225 ) .
"""
class SongForm ( forms . ModelForm ) :
extra_data = forms . CharField ( )
class Meta :
model = Song
class FieldsOnFormOnlyAdmin ( admin . ModelAdmin ) :
form = SongForm
fields = [ ' extra_data ' , ' title ' ]
validate ( FieldsOnFormOnlyAdmin , Song )