Ticket #3222: 3222-newforms-admin.patch
File 3222-newforms-admin.patch, 33.8 KB (added by , 18 years ago) |
---|
-
django/contrib/admin/options.py
113 113 prepopulated_fields = {} 114 114 filter_vertical = () 115 115 filter_horizontal = () 116 option_errors = None 116 117 117 118 def __init__(self, model): 118 119 self.model = model … … 117 118 def __init__(self, model): 118 119 self.model = model 119 120 self.opts = model._meta 121 self.validate_options() 120 122 121 123 def __call__(self, request, url): 122 124 # Check that LogEntry, ContentType and the auth context processor are installed. … … 264 266 265 267 def change_list_queryset(self, request): 266 268 return self.model._default_manager.get_query_set() 269 270 def validate_options(self): 271 """ 272 Hook for validating admin options, returns a list of all errors. 273 """ 274 opts = self.opts 275 cls = self.model 276 errors = self.option_errors = [] 277 model_fields = [f.name for f in opts.fields + opts.many_to_many] 278 model_attr = dir(cls) 279 280 # helper lambda functions to write out common errors 281 listError = lambda option: errors.append('"%s", if given, must be set to a list or tuple.' % option) 282 dictError = lambda option: errors.append('"%s", if given, must be a dictionary.' % option) 283 boolError = lambda option: errors.append('"%s", if given, must be set to True or False.' % option) 284 intError = lambda option: errors.append('"%s", if given, must be a positive integer.' % option) 285 twoTupleError = lambda option: errors.append('"%s", if given, must be a list or tuple of 2-tuples.' % option) 286 fieldError = lambda option, fn: errors.append('"%(opt_name)s" refers to %(field_name)r, which is not a field.' % {'opt_name': option, 'field_name': fn}) 287 fieldAttrError = lambda option, fn: errors.append('"%(opt_name)s" refers to %(field_name)r, which is not an attribute, method or property.' % {'opt_name': option, 'field_name': fn}) 288 dateFieldError = lambda option, fn: errors.append('"%(opt_name)s" refers to %(field_name)r, which is not a DateField or DateTimeField.' % {'opt_name': option, 'field_name': fn}) 289 m2mFieldError = lambda option, fn: errors.append('"%(opt_name)s" does not support ManyToMany fields %(field_name)r.' % {'opt_name': option, 'field_name': fn}) 290 listDisplayError = lambda option, fn: errors.append('"%(opt_name)s" refers to %(field_name)r, which is not defined in "list_display".' % {'opt_name': option, 'field_name': fn}) 291 missingFieldOptError = lambda option: errors.append('"fields", field_options dict %r must include a fields option.' % option) 292 293 # helper lambda functions to check if item is valid 294 checkField = lambda fn: fn in model_fields 295 checkAttrField = lambda fn: fn in (model_fields + model_attr) 296 297 def __recursiveCheckField(item, option): 298 """Recursive helper function checks all nested lists/tuples for valid fields""" 299 if isinstance(item, (list, tuple)): 300 [__recursiveCheckField(fn, option) for fn in item] 301 elif not checkField(item): 302 fieldError(option, item) 303 304 # prepopulated_fields 305 if not isinstance(self.prepopulated_fields, dict): 306 dictError('prepopulated_fields') 307 else: 308 for field_name, field_list in self.prepopulated_fields.items(): 309 if not checkField(field_name): 310 fieldError('prepopulated_fields', field_name) 311 if not isinstance(field_list, (list, tuple)): 312 listError('prepopulated_fields - dependencies') 313 else: 314 [fieldError('prepopulated_fields', fn) for fn in field_list if not checkField(fn)] 315 316 #fields 317 if self.fields: 318 if not isinstance(self.fields, (list, tuple)): 319 listError('fields') 320 else: 321 try: 322 for name, options in self.fields: 323 if not isinstance(options, dict): 324 dictError('fields - field_options') 325 else: 326 field_tuple = options.get('fields', None) 327 if not field_tuple: 328 missingFieldOptError(options) 329 elif not isinstance(field_tuple, (list, tuple)): 330 listError('fields - fieldset') 331 else: 332 __recursiveCheckField(field_tuple, 'fields') 333 except ValueError: 334 twoTupleError('fields') 335 336 #list_display 337 if not isinstance(self.list_display, (list, tuple)): 338 listError('list_display') 339 else: 340 for fn in self.list_display: 341 if not checkAttrField(fn): 342 fieldAttrError('list_display', fn) 343 elif checkField(fn) and isinstance(opts.get_field(fn), models.ManyToManyField): 344 m2mFieldError('list_display', fn) 345 346 #list_display_links 347 if not isinstance(self.list_display_links, (list, tuple)): 348 listError('list_display_links') 349 else: 350 for fn in self.list_display_links: 351 if fn not in self.list_display: 352 listDisplayError('list_display_links', fn) 267 353 354 #list_filter 355 if not isinstance(self.list_filter, (list, tuple)): 356 listError('list_filter') 357 else: 358 [fieldError('list_filter', fn) for fn in self.list_filter if not checkField(fn)] 359 360 #date_hierarchy 361 if self.date_hierarchy: 362 if not checkField(self.date_hierarchy): 363 fieldError('date_hierarchy', self.date_hierarchy) 364 elif not isinstance(opts.get_field(self.date_hierarchy), (models.DateField, models.DateTimeField)): 365 dateFieldError('date_hierarchy', self.date_hierarchy) 366 367 #search_fields 368 if not isinstance(self.search_fields, (list, tuple)): 369 listError('search_fields') 370 else: 371 # search_fields can use the related lookup API 'follow' notation. 372 [fieldError('search_fields', fn) for fn in self.search_fields if not checkField(fn.split('__')[0])] 373 374 #raw_id_fields 375 if not isinstance(self.raw_id_fields, (list, tuple)): 376 listError('raw_id_fields') 377 else: 378 [fieldError('raw_id_fields', fn) for fn in self.raw_id_fields if not checkField(fn)] 379 380 #filter_vertical 381 if not isinstance(self.filter_vertical, (list, tuple)): 382 listError('filter_vertical') 383 else: 384 [fieldError('filter_vertical', fn) for fn in self.filter_vertical if not checkField(fn)] 385 386 #filter_horizontal 387 if not isinstance(self.filter_horizontal, (list, tuple)): 388 listError('filter_horizontal') 389 else: 390 [fieldError('filter_horizontal', fn) for fn in self.filter_horizontal if not checkField(fn)] 391 392 #js 393 if self.js and not isinstance(self.js, (list, tuple)): 394 listError('js') 395 396 #save_as 397 if self.save_as not in (True, False): 398 boolError('save_as') 399 400 #save_on_top 401 if self.save_on_top not in (True, False): 402 boolError('save_on_top') 403 404 #list_select_related 405 if self.list_select_related not in (True, False): 406 boolError('list_select_related') 407 408 #list_per_page 409 try: 410 if int(self.list_per_page) < 0: 411 intError('list_per_page') 412 except ValueError: 413 intError('list_per_page') 414 415 #ordering 416 if self.ordering: 417 if not isinstance(self.ordering, (list, tuple)): 418 listError('ordering') 419 else: 420 for fn in self.ordering: 421 if fn.startswith('-'): 422 fn = fn.split('-')[1] 423 if not checkField(fn): 424 fieldError('ordering', fn) 425 268 426 def add_view(self, request, form_url='', post_url_continue='../%s/'): 269 427 "The 'add' admin view for this model." 270 428 from django.contrib.admin.views.main import render_change_form -
django/core/management.py
977 977 978 978 # Check admin attribute. 979 979 if opts.admin is not None: 980 # prepopulated_fields 981 if not isinstance(opts.admin.prepopulated_fields, dict): 982 e.add(opts, '"%s": prepopulated_fields should be a dictionary.' % f.name) 983 else: 984 for field_name, field_list in opts.admin.prepopulated_fields.items(): 985 if not isinstance(field_list, (list, tuple)): 986 e.add(opts, '"%s": prepopulated_fields "%s" value should be a list or tuple.' % (f.name, field_name)) 987 988 # list_display 989 if not isinstance(opts.admin.list_display, (list, tuple)): 990 e.add(opts, '"admin.list_display", if given, must be set to a list or tuple.') 991 else: 992 for fn in opts.admin.list_display: 993 try: 994 f = opts.get_field(fn) 995 except models.FieldDoesNotExist: 996 if not hasattr(cls, fn): 997 e.add(opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn) 998 else: 999 if isinstance(f, models.ManyToManyField): 1000 e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn) 1001 # list_display_links 1002 if opts.admin.list_display_links and not opts.admin.list_display: 1003 e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.') 1004 if not isinstance(opts.admin.list_display_links, (list, tuple)): 1005 e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.') 1006 else: 1007 for fn in opts.admin.list_display_links: 1008 try: 1009 f = opts.get_field(fn) 1010 except models.FieldDoesNotExist: 1011 if not hasattr(cls, fn): 1012 e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn) 1013 if fn not in opts.admin.list_display: 1014 e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn) 1015 # list_filter 1016 if not isinstance(opts.admin.list_filter, (list, tuple)): 1017 e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.') 1018 else: 1019 for fn in opts.admin.list_filter: 1020 try: 1021 f = opts.get_field(fn) 1022 except models.FieldDoesNotExist: 1023 e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) 1024 # date_hierarchy 1025 if opts.admin.date_hierarchy: 1026 try: 1027 f = opts.get_field(opts.admin.date_hierarchy) 1028 except models.FieldDoesNotExist: 1029 e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy) 980 for error in opts.admin(cls).option_errors: 981 e.add(opts, error) 1030 982 1031 983 # Check ordering attribute. 1032 984 if opts.ordering: -
tests/modeltests/invalid_models/models.py
10 10 charfield = models.CharField() 11 11 floatfield = models.FloatField() 12 12 filefield = models.FileField() 13 prepopulate = models.CharField(maxlength=10, prepopulate_from='bad')14 13 choices = models.CharField(maxlength=10, choices='bad') 15 14 choices2 = models.CharField(maxlength=10, choices=[(1,2,3),(1,2,3)]) 16 15 index = models.CharField(maxlength=10, db_index='bad') … … 101 100 invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute. 102 101 invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute. 103 102 invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. 104 invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple.105 103 invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list). 106 104 invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. 107 105 invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-tuples. -
tests/regressiontests/invalid_admin_options/models.py
15 15 class Admin: 16 16 list_display = 'first_name' 17 17 18 model_errors += """invalid_admin_options.listdisplaybadone: " admin.list_display", if given, must be set to a list or tuple.18 model_errors += """invalid_admin_options.listdisplaybadone: "list_display", if given, must be set to a list or tuple. 19 19 """ 20 20 21 21 class ListDisplayBadTwo(models.Model): … … 25 25 class Admin: 26 26 list_display = ['first_name','nonexistent'] 27 27 28 model_errors += """invalid_admin_options.listdisplaybadtwo: " admin.list_display" refers to 'nonexistent', which isn't an attribute, method or property.28 model_errors += """invalid_admin_options.listdisplaybadtwo: "list_display" refers to 'nonexistent', which is not an attribute, method or property. 29 29 """ 30 30 class ListDisplayBadThree(models.Model): 31 31 "Test list_display, list_display items can not be a ManyToManyField." … … 35 35 class Admin: 36 36 list_display = ['first_name','nick_names'] 37 37 38 model_errors += """invalid_admin_options.listdisplaybadthree: " admin.list_display" doesn't support ManyToManyFields ('nick_names').38 model_errors += """invalid_admin_options.listdisplaybadthree: "list_display" does not support ManyToMany fields 'nick_names'. 39 39 """ 40 40 41 41 class ListDisplayGood(models.Model): … … 61 61 list_display = ['last_name'] 62 62 list_display_links = ['first_name'] 63 63 64 model_errors += """invalid_admin_options.listdisplaylinksbadone: " admin.list_display_links" refers to 'first_name', which is not defined in "admin.list_display".64 model_errors += """invalid_admin_options.listdisplaylinksbadone: "list_display_links" refers to 'first_name', which is not defined in "list_display". 65 65 """ 66 66 67 67 class ListDisplayLinksBadTwo(models.Model): … … 73 73 list_display = ['first_name','last_name'] 74 74 list_display_links = 'last_name' 75 75 76 model_errors += """invalid_admin_options.listdisplaylinksbadtwo: " admin.list_display_links", if given, must be set to a list or tuple.76 model_errors += """invalid_admin_options.listdisplaylinksbadtwo: "list_display_links", if given, must be set to a list or tuple. 77 77 """ 78 79 # TODO: Fix list_display_links validation or remove the check for list_display80 ## This is failing but the validation which should fail is not.81 #class ListDisplayLinksBadThree(models.Model):82 # "Test list_display_links, must define list_display to use list_display_links."83 # first_name = models.CharField(maxlength=30)84 # last_name = models.CharField(maxlength=30)85 #86 # class Admin:87 # list_display_links = ('first_name',)88 #89 #model_errors += """invalid_admin_options.listdisplaylinksbadthree: "admin.list_display" must be defined for "admin.list_display_links" to be used.90 #"""91 78 92 79 class ListDisplayLinksGood(models.Model): 93 80 "Test list_display_links, Admin list_display_list can be a attribute, method or property." … … 111 98 class Admin: 112 99 list_filter = 'first_name' 113 100 114 model_errors += """invalid_admin_options.listfilterbadone: " admin.list_filter", if given, must be set to a list or tuple.101 model_errors += """invalid_admin_options.listfilterbadone: "list_filter", if given, must be set to a list or tuple. 115 102 """ 116 103 117 104 class ListFilterBadTwo(models.Model): … … 128 115 class Admin: 129 116 list_filter = ['first_name','last_name','full_name'] 130 117 131 model_errors += """invalid_admin_options.listfilterbadtwo: " admin.list_filter" refers to 'last_name', which isn't a field.132 invalid_admin_options.listfilterbadtwo: " admin.list_filter" refers to 'full_name', which isn't a field.118 model_errors += """invalid_admin_options.listfilterbadtwo: "list_filter" refers to 'last_name', which is not a field. 119 invalid_admin_options.listfilterbadtwo: "list_filter" refers to 'full_name', which is not a field. 133 120 """ 134 121 135 122 class DateHierarchyBadOne(models.Model): … … 140 127 class Admin: 141 128 date_hierarchy = 'first_name' 142 129 143 # TODO: Date Hierarchy needs to check if field is a date/datetime field. 144 #model_errors += """invalid_admin_options.datehierarchybadone: "admin.date_hierarchy" refers to 'first_name', which isn't a date field or datetime field. 145 #""" 130 model_errors += """invalid_admin_options.datehierarchybadone: "date_hierarchy" refers to 'first_name', which is not a DateField or DateTimeField. 131 """ 146 132 147 133 class DateHierarchyBadTwo(models.Model): 148 134 "Test date_hieracrhy, must be a field." … … 152 138 class Admin: 153 139 date_hierarchy = 'nonexistent' 154 140 155 model_errors += """invalid_admin_options.datehierarchybadtwo: " admin.date_hierarchy" refers to 'nonexistent', which isn't a field.141 model_errors += """invalid_admin_options.datehierarchybadtwo: "date_hierarchy" refers to 'nonexistent', which is not a field. 156 142 """ 157 143 158 144 class DateHierarchyGood(models.Model): … … 170 156 class Admin: 171 157 search_fields = ('nonexistent') 172 158 173 # TODO: Add search_fields validation 174 #model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields", if given, must be set to a list or tuple. 175 #""" 159 model_errors += """invalid_admin_options.searchfieldsbadone: "search_fields", if given, must be set to a list or tuple. 160 """ 176 161 177 162 class SearchFieldsBadTwo(models.Model): 178 163 "Test search_fields, must be a field." … … 185 170 class Admin: 186 171 search_fields = ['first_name','last_name'] 187 172 188 # TODO: Add search_fields validation 189 #model_errors += """invalid_admin_options.seacrhfieldsbadone: "admin.search_fields" refers to 'last_name', which isn't a field. 190 #""" 173 model_errors += """invalid_admin_options.searchfieldsbadtwo: "search_fields" refers to 'last_name', which is not a field. 174 """ 191 175 192 176 class SearchFieldsGood(models.Model): 193 177 "Test search_fields, must be a list or tuple." … … 197 181 class Admin: 198 182 search_fields = ['first_name','last_name'] 199 183 184 class SearchFieldsGoodTwo(models.Model): 185 "Test search_fields, related lookup API 'follow' syntax allowed." 186 first_name = models.CharField(maxlength=30) 187 last = models.ForeignKey(SearchFieldsGood) 188 189 class Admin: 190 search_fields = ['first_name','last__last_name'] 200 191 201 192 class JsBadOne(models.Model): 202 193 "Test js, must be a list or tuple" … … 204 195 205 196 class Admin: 206 197 js = 'test.js' 207 208 # TODO: Add a js validator 209 #model_errors += """invalid_admin_options.jsbadone: "admin.js", if given, must be set to a list or tuple. 210 #""" 198 199 model_errors += """invalid_admin_options.jsbadone: "js", if given, must be set to a list or tuple. 200 """ 211 201 212 202 class SaveAsBad(models.Model): 213 203 "Test save_as, should be True or False" … … 215 205 216 206 class Admin: 217 207 save_as = 'not True or False' 218 219 # TODO: Add a save_as validator. 220 #model_errors += """invalid_admin_options.saveasbad: "admin.save_as", if given, must be set to True or False. 221 #""" 208 209 model_errors += """invalid_admin_options.saveasbad: "save_as", if given, must be set to True or False. 210 """ 222 211 223 212 class SaveOnTopBad(models.Model): 224 213 "Test save_on_top, should be True or False" … … 226 215 227 216 class Admin: 228 217 save_on_top = 'not True or False' 229 230 # TODO: Add a save_on_top validator. 231 #model_errors += """invalid_admin_options.saveontopbad: "admin.save_on_top", if given, must be set to True or False. 232 #""" 218 219 model_errors += """invalid_admin_options.saveontopbad: "save_on_top", if given, must be set to True or False. 220 """ 233 221 234 222 class ListSelectRelatedBad(models.Model): 235 223 "Test list_select_related, should be True or False" … … 237 225 238 226 class Admin: 239 227 list_select_related = 'not True or False' 240 241 # TODO: Add a list_select_related validator. 242 #model_errors += """invalid_admin_options.listselectrelatebad: "admin.list_select_related", if given, must be set to True or False. 243 #""" 228 229 model_errors += """invalid_admin_options.listselectrelatedbad: "list_select_related", if given, must be set to True or False. 230 """ 244 231 245 232 class ListPerPageBad(models.Model): 246 233 "Test list_per_page, should be a positive integer value." … … 247 234 name = models.CharField(maxlength=30) 248 235 249 236 class Admin: 250 list_per_page = 89.3 237 list_per_page = -89.3 238 239 model_errors += """invalid_admin_options.listperpagebad: "list_per_page", if given, must be a positive integer. 240 """ 251 241 252 # TODO: Add a list_per_page validator. 253 #model_errors += """invalid_admin_options.listperpagebad: "admin.list_per_page", if given, must be a positive integer. 254 #""" 242 class ListPerPageBadTwo(models.Model): 243 "Test list_per_page, should be a positive integer value." 244 name = models.CharField(maxlength=30) 245 246 class Admin: 247 list_per_page = "not a number" 248 249 model_errors += """invalid_admin_options.listperpagebadtwo: "list_per_page", if given, must be a positive integer. 250 """ 255 251 256 252 class FieldsBadOne(models.Model): 257 253 "Test fields, should be a tuple" … … 260 256 261 257 class Admin: 262 258 fields = 'not a tuple' 263 264 # TODO: Add a fields validator. 265 #model_errors += """invalid_admin_options.fieldsbadone: "admin.fields", if given, must be a tuple. 266 #""" 259 260 model_errors += """invalid_admin_options.fieldsbadone: "fields", if given, must be set to a list or tuple. 261 """ 267 262 268 263 class FieldsBadTwo(models.Model): 269 264 """Test fields, 'fields' dict option is required.""" … … 271 266 last_name = models.CharField(maxlength=30) 272 267 273 268 class Admin: 274 fields = ('Name', {'description': 'this fieldset needs fields'}) 275 276 # TODO: Add a fields validator. 277 #model_errors += """invalid_admin_options.fieldsbadtwo: "admin.fields" each fieldset must include a 'fields' dict. 278 #""" 269 fields = (('Name', {'description': 'this fieldset needs fields'}),) 270 271 model_errors += """invalid_admin_options.fieldsbadtwo: "fields", field_options dict {'description': 'this fieldset needs fields'} must include a fields option. 272 """ 279 273 280 274 class FieldsBadThree(models.Model): 281 """Test fields, 'classes' and 'description' are the only allowable extra dict options."""275 """Test fields, must be a list or tuple of 2-tuples.""" 282 276 first_name = models.CharField(maxlength=30) 283 277 last_name = models.CharField(maxlength=30) 284 278 … … 283 277 last_name = models.CharField(maxlength=30) 284 278 285 279 class Admin: 286 fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'}) 280 fields = (('Name', {'fields': ('first_name','last_name')},'badoption'),) 281 282 model_errors += """invalid_admin_options.fieldsbadthree: "fields", if given, must be a list or tuple of 2-tuples. 283 """ 287 284 288 # TODO: Add a fields validator. 289 #model_errors += """invalid_admin_options.fieldsbadthree: "admin.fields" fieldset options must be either 'classes' or 'description'. 290 #""" 285 class FieldsBadFour(models.Model): 286 """Test fields, 'fields' dict option must be fields.""" 287 first_name = models.CharField(maxlength=30) 288 last_name = models.CharField(maxlength=30) 289 290 class Admin: 291 fields = ( 292 ('Name', {'fields': ('first_name','nonexistent')}), 293 (None, {'fields': ('first_name', ('also_bad','last_name'))}), 294 (None, {'fields': ((('last_name','bad3'),'bad2'),'bad1')}), 295 ) 296 297 model_errors += """invalid_admin_options.fieldsbadfour: "fields" refers to 'nonexistent', which is not a field. 298 invalid_admin_options.fieldsbadfour: "fields" refers to 'also_bad', which is not a field. 299 invalid_admin_options.fieldsbadfour: "fields" refers to 'bad3', which is not a field. 300 invalid_admin_options.fieldsbadfour: "fields" refers to 'bad2', which is not a field. 301 invalid_admin_options.fieldsbadfour: "fields" refers to 'bad1', which is not a field. 302 """ 303 304 class FieldsBadFive(models.Model): 305 """Test fields, field_options must be a dict""" 306 first_name = models.CharField(maxlength=30) 307 last_name = models.CharField(maxlength=30) 308 309 class Admin: 310 fields = (('Name', ('first_name','last_name')),) 311 312 model_errors += """invalid_admin_options.fieldsbadfive: "fields - field_options", if given, must be a dictionary. 313 """ 291 314 292 315 class FieldsGood(models.Model): 293 316 "Test fields, working example" … … 297 320 298 321 class Admin: 299 322 fields = ( 300 ('Name', {'fields': ('first_name','last_name'),'classes': 'collapse '}),323 ('Name', {'fields': ('first_name','last_name'),'classes': 'collapse wide'}), 301 324 (None, {'fields': ('birth_day',),'description': 'enter your b-day'}) 302 325 ) 303 326 … … 302 325 ) 303 326 304 327 class OrderingBad(models.Model): 328 "Test ordering, must be a list or tuple" 329 first_name = models.CharField(maxlength=30) 330 last_name = models.CharField(maxlength=30) 331 332 class Admin: 333 ordering = 'not_a_list' 334 335 model_errors += """invalid_admin_options.orderingbad: "ordering", if given, must be set to a list or tuple. 336 """ 337 338 class OrderingBadTwo(models.Model): 305 339 "Test ordering, must be a field." 306 340 first_name = models.CharField(maxlength=30) 307 341 last_name = models.CharField(maxlength=30) … … 307 341 last_name = models.CharField(maxlength=30) 308 342 309 343 class Admin: 310 ordering = 'nonexistent' 344 ordering = ['nonexistent'] 345 346 model_errors += """invalid_admin_options.orderingbadtwo: "ordering" refers to 'nonexistent', which is not a field. 347 """ 311 348 312 # TODO: Add a ordering validator. 313 #model_errors += """invalid_admin_options.orderingbad: "admin.ordering" refers to 'nonexistent', which isn't a field. 314 #""" 349 class OrderingGood(models.Model): 350 "Test ordering, can reverse sort by prepending a '-' to the fieldname." 351 first_name = models.CharField(maxlength=30) 352 last_name = models.CharField(maxlength=30) 353 354 class Admin: 355 ordering = ['-first_name'] 315 356 316 ## TODO: Add a manager validator, this should fail gracefully. 317 #class ManagerBad(models.Model): 318 # "Test manager, must be a manager object." 319 # first_name = models.CharField(maxlength=30) 320 # 321 # class Admin: 322 # manager = 'nonexistent' 323 # 324 #model_errors += """invalid_admin_options.managerbad: "admin.manager" refers to 'nonexistent', which isn't a Manager(). 325 #""" 357 class PrepopulatedFieldsBadOne(models.Model): 358 "Test prepopulated_fields, must be a dictionary" 359 first_name = models.CharField(maxlength=30) 360 last_name = models.CharField(maxlength=30) 361 slug = models.SlugField() 362 363 class Admin: 364 prepopulated_fields = ('slug',('first_name','last_name')) 365 366 model_errors += """invalid_admin_options.prepopulatedfieldsbadone: "prepopulated_fields", if given, must be a dictionary. 367 """ 368 369 class PrepopulatedFieldsBadTwo(models.Model): 370 "Test prepopulated_fields, must be fields" 371 first_name = models.CharField(maxlength=30) 372 last_name = models.CharField(maxlength=30) 373 slug = models.SlugField() 374 375 class Admin: 376 prepopulated_fields = {'slug': ('first_name','last_name'), 377 'nonexistent': ('bad1','bad2')} 378 379 model_errors += """invalid_admin_options.prepopulatedfieldsbadtwo: "prepopulated_fields" refers to 'nonexistent', which is not a field. 380 invalid_admin_options.prepopulatedfieldsbadtwo: "prepopulated_fields" refers to 'bad1', which is not a field. 381 invalid_admin_options.prepopulatedfieldsbadtwo: "prepopulated_fields" refers to 'bad2', which is not a field. 382 """ 383 384 class PrepopulatedFieldsBadThree(models.Model): 385 "Test prepopulated_fields, dependencies must be a list or tuple of fields" 386 first_name = models.CharField(maxlength=30) 387 last_name = models.CharField(maxlength=30) 388 slug = models.SlugField() 389 390 class Admin: 391 prepopulated_fields = {'slug': 'not a list or tuple'} 392 393 model_errors += """invalid_admin_options.prepopulatedfieldsbadthree: "prepopulated_fields - dependencies", if given, must be set to a list or tuple. 394 """ 395 class PrepopulatedFieldsGood(models.Model): 396 "Test prepopulated_fields, must be fields" 397 first_name = models.CharField(maxlength=30) 398 last_name = models.CharField(maxlength=30) 399 slug = models.SlugField() 400 401 class Admin: 402 prepopulated_fields = {'slug': ('first_name','last_name')} 403 404 class RawIdFieldsBadOne(models.Model): 405 "Test raw_id_fields, must be a list or tuple of fields" 406 user = models.ForeignKey(PrepopulatedFieldsGood) 407 widget_id = models.PositiveIntegerField() 408 409 class Admin: 410 raw_id_fields = 'user' 411 412 model_errors += """invalid_admin_options.rawidfieldsbadone: "raw_id_fields", if given, must be set to a list or tuple. 413 """ 414 415 class RawIdFieldsBadTwo(models.Model): 416 "Test raw_id_fields, must be fields" 417 user = models.ForeignKey(PrepopulatedFieldsGood) 418 widget_id = models.PositiveIntegerField() 419 420 class Admin: 421 raw_id_fields = ('bad1','bad2') 422 423 model_errors += """invalid_admin_options.rawidfieldsbadtwo: "raw_id_fields" refers to 'bad1', which is not a field. 424 invalid_admin_options.rawidfieldsbadtwo: "raw_id_fields" refers to 'bad2', which is not a field. 425 """ 426 427 class RawIdFieldsGood(models.Model): 428 "Test raw_id_fields, must be fields" 429 user = models.ForeignKey(PrepopulatedFieldsGood) 430 widget_id = models.PositiveIntegerField() 431 432 class Admin: 433 raw_id_fields = ('user','widget_id') 434 435 class FilterHVBadOne(models.Model): 436 "Test filter_horizontal and filter_vertical, must be a list or tuple of fields." 437 name = models.CharField(maxlength=30) 438 widgets = models.ManyToManyField(RawIdFieldsGood) 439 other_widgets = models.ManyToManyField(RawIdFieldsBadTwo) 440 441 class Admin: 442 filter_horizontal = 'widgets' 443 filter_vertical = 'other_widgets' 444 445 model_errors += """invalid_admin_options.filterhvbadone: "filter_horizontal", if given, must be set to a list or tuple. 446 invalid_admin_options.filterhvbadone: "filter_vertical", if given, must be set to a list or tuple. 447 """ 448 449 class FilterHVBadTwo(models.Model): 450 "Test filter_horizontal, must be a list or tuple of fields." 451 name = models.CharField(maxlength=30) 452 widgets = models.ManyToManyField(RawIdFieldsGood) 453 other_widgets = models.ManyToManyField(RawIdFieldsBadTwo) 454 455 class Admin: 456 filter_horizontal = ('nonexistent',) 457 filter_vertical = ('also_nonexistent',) 458 459 model_errors += """invalid_admin_options.filterhvbadtwo: "filter_horizontal" refers to 'nonexistent', which is not a field. 460 invalid_admin_options.filterhvbadtwo: "filter_vertical" refers to 'also_nonexistent', which is not a field. 461 """ 462 463 class FilterHVGood(models.Model): 464 "Test filter_horizontal" 465 name = models.CharField(maxlength=30) 466 widgets = models.ManyToManyField(RawIdFieldsGood) 467 other_widgets = models.ManyToManyField(RawIdFieldsBadTwo) 468 469 class Admin: 470 filter_horizontal = ('widgets',) 471 filter_vertical = ('other_widgets',) 472 473 class MuiltpleAdminErrors(models.Model): 474 "Test multiple errors, all errors should be collected" 475 name = models.CharField(maxlength=30) 476 477 class Admin: 478 list_display = 'name' 479 list_filter = 'name' 480 fields = (("wrong", {'fields': 'name'}),) 481 search_fields = 'name' 482 date_hierarchy = 'name' 483 ordering = 'name' 484 485 model_errors += """invalid_admin_options.muiltpleadminerrors: "fields - fieldset", if given, must be set to a list or tuple. 486 invalid_admin_options.muiltpleadminerrors: "list_display", if given, must be set to a list or tuple. 487 invalid_admin_options.muiltpleadminerrors: "list_filter", if given, must be set to a list or tuple. 488 invalid_admin_options.muiltpleadminerrors: "date_hierarchy" refers to 'name', which is not a DateField or DateTimeField. 489 invalid_admin_options.muiltpleadminerrors: "search_fields", if given, must be set to a list or tuple. 490 invalid_admin_options.muiltpleadminerrors: "ordering", if given, must be set to a list or tuple. 491 """ 492 493 class IgnoreMultipleErrors(models.Model): 494 "validate_options can be overridden to change its behavior" 495 name = models.CharField(maxlength=30) 496 497 class Admin: 498 list_display = 'name' 499 list_filter = 'name' 500 fields = (("wrong", {'fields': 'name'}),) 501 search_fields = 'name' 502 date_hierarchy = 'name' 503 ordering = 'name' 504 def validate_options(self): 505 # Don't validate any options and allow the model to be created. 506 self.option_errors = [] 507 No newline at end of file