| 1 |
Index: django/core/management/validation.py |
|---|
| 2 |
=================================================================== |
|---|
| 3 |
--- django/core/management/validation.py (revision 7884) |
|---|
| 4 |
+++ django/core/management/validation.py (working copy) |
|---|
| 5 |
@@ -143,59 +143,6 @@ |
|---|
| 6 |
if r.get_accessor_name() == rel_query_name: |
|---|
| 7 |
e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) |
|---|
| 8 |
|
|---|
| 9 |
- # Check admin attribute. |
|---|
| 10 |
- if opts.admin is not None: |
|---|
| 11 |
- # prepopulated_fields |
|---|
| 12 |
- if not isinstance(opts.admin.prepopulated_fields, dict): |
|---|
| 13 |
- e.add(opts, '"%s": prepopulated_fields should be a dictionary.' % f.name) |
|---|
| 14 |
- else: |
|---|
| 15 |
- for field_name, field_list in opts.admin.prepopulated_fields.items(): |
|---|
| 16 |
- if not isinstance(field_list, (list, tuple)): |
|---|
| 17 |
- e.add(opts, '"%s": prepopulated_fields "%s" value should be a list or tuple.' % (f.name, field_name)) |
|---|
| 18 |
- |
|---|
| 19 |
- # list_display |
|---|
| 20 |
- if not isinstance(opts.admin.list_display, (list, tuple)): |
|---|
| 21 |
- e.add(opts, '"admin.list_display", if given, must be set to a list or tuple.') |
|---|
| 22 |
- else: |
|---|
| 23 |
- for fn in opts.admin.list_display: |
|---|
| 24 |
- try: |
|---|
| 25 |
- f = opts.get_field(fn) |
|---|
| 26 |
- except models.FieldDoesNotExist: |
|---|
| 27 |
- if not hasattr(cls, fn): |
|---|
| 28 |
- e.add(opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn) |
|---|
| 29 |
- else: |
|---|
| 30 |
- if isinstance(f, models.ManyToManyField): |
|---|
| 31 |
- e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn) |
|---|
| 32 |
- # list_display_links |
|---|
| 33 |
- if opts.admin.list_display_links and not opts.admin.list_display: |
|---|
| 34 |
- e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.') |
|---|
| 35 |
- if not isinstance(opts.admin.list_display_links, (list, tuple)): |
|---|
| 36 |
- e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.') |
|---|
| 37 |
- else: |
|---|
| 38 |
- for fn in opts.admin.list_display_links: |
|---|
| 39 |
- try: |
|---|
| 40 |
- f = opts.get_field(fn) |
|---|
| 41 |
- except models.FieldDoesNotExist: |
|---|
| 42 |
- if not hasattr(cls, fn): |
|---|
| 43 |
- e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn) |
|---|
| 44 |
- if fn not in opts.admin.list_display: |
|---|
| 45 |
- e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn) |
|---|
| 46 |
- # list_filter |
|---|
| 47 |
- if not isinstance(opts.admin.list_filter, (list, tuple)): |
|---|
| 48 |
- e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.') |
|---|
| 49 |
- else: |
|---|
| 50 |
- for fn in opts.admin.list_filter: |
|---|
| 51 |
- try: |
|---|
| 52 |
- f = opts.get_field(fn) |
|---|
| 53 |
- except models.FieldDoesNotExist: |
|---|
| 54 |
- e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) |
|---|
| 55 |
- # date_hierarchy |
|---|
| 56 |
- if opts.admin.date_hierarchy: |
|---|
| 57 |
- try: |
|---|
| 58 |
- f = opts.get_field(opts.admin.date_hierarchy) |
|---|
| 59 |
- except models.FieldDoesNotExist: |
|---|
| 60 |
- e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy) |
|---|
| 61 |
- |
|---|
| 62 |
# Check ordering attribute. |
|---|
| 63 |
if opts.ordering: |
|---|
| 64 |
for field_name in opts.ordering: |
|---|
| 65 |
@@ -213,18 +160,6 @@ |
|---|
| 66 |
except models.FieldDoesNotExist: |
|---|
| 67 |
e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) |
|---|
| 68 |
|
|---|
| 69 |
- # Check core=True, if needed. |
|---|
| 70 |
- for related in opts.get_followed_related_objects(): |
|---|
| 71 |
- if not related.edit_inline: |
|---|
| 72 |
- continue |
|---|
| 73 |
- try: |
|---|
| 74 |
- for f in related.opts.fields: |
|---|
| 75 |
- if f.core: |
|---|
| 76 |
- raise StopIteration |
|---|
| 77 |
- e.add(related.opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (related.opts.object_name, opts.module_name, opts.object_name)) |
|---|
| 78 |
- except StopIteration: |
|---|
| 79 |
- pass |
|---|
| 80 |
- |
|---|
| 81 |
# Check unique_together. |
|---|
| 82 |
for ut in opts.unique_together: |
|---|
| 83 |
for field_name in ut: |
|---|
| 84 |
Index: django/contrib/admin/validation.py |
|---|
| 85 |
=================================================================== |
|---|
| 86 |
--- django/contrib/admin/validation.py (revision 0) |
|---|
| 87 |
+++ django/contrib/admin/validation.py (revision 0) |
|---|
| 88 |
@@ -0,0 +1,271 @@ |
|---|
| 89 |
+# Possible improvements: gather all errors and raise in the end instead of |
|---|
| 90 |
+# bailing out on the first one (like core/management/validation.py does) |
|---|
| 91 |
+ |
|---|
| 92 |
+from django.core.exceptions import ImproperlyConfigured |
|---|
| 93 |
+from django.db import models |
|---|
| 94 |
+from django import newforms as forms |
|---|
| 95 |
+from django.contrib.admin.options import flatten_fieldsets, BaseModelAdmin |
|---|
| 96 |
+from django.contrib.admin.options import HORIZONTAL, VERTICAL |
|---|
| 97 |
+ |
|---|
| 98 |
+def validate(cls, model): |
|---|
| 99 |
+ """ |
|---|
| 100 |
+ Does basic ModelAdmin option validation. Calls custom validation |
|---|
| 101 |
+ classmethod in the end if it is provided in cls. The signature of the |
|---|
| 102 |
+ custom validation classmethod should be: def validate(cls, model). |
|---|
| 103 |
+ """ |
|---|
| 104 |
+ opts = model._meta |
|---|
| 105 |
+ _validate_base(cls, model) |
|---|
| 106 |
+ |
|---|
| 107 |
+ # currying is expensive, use wrappers instead |
|---|
| 108 |
+ def _check_istuplew(label, obj): |
|---|
| 109 |
+ _check_istuple(cls, label, obj) |
|---|
| 110 |
+ |
|---|
| 111 |
+ def _check_isdictw(label, obj): |
|---|
| 112 |
+ _check_isdict(cls, label, obj) |
|---|
| 113 |
+ |
|---|
| 114 |
+ def _check_field_existsw(label, field): |
|---|
| 115 |
+ return _check_field_exists(cls, model, opts, label, field) |
|---|
| 116 |
+ |
|---|
| 117 |
+ def _check_attr_existsw(label, field): |
|---|
| 118 |
+ _check_attr_exists(cls, model, opts, label, field) |
|---|
| 119 |
+ |
|---|
| 120 |
+ # list_display |
|---|
| 121 |
+ if not cls.list_display: |
|---|
| 122 |
+ raise ImproperlyConfigured("%s.list_display can not be empty." % |
|---|
| 123 |
+ cls.__name__) |
|---|
| 124 |
+ _check_istuplew('list_display', cls.list_display) |
|---|
| 125 |
+ for idx, field in enumerate(cls.list_display): |
|---|
| 126 |
+ f = _check_attr_existsw("list_display['%d']" % idx, field) |
|---|
| 127 |
+ if isinstance(f, models.ManyToManyField): |
|---|
| 128 |
+ raise ImproperlyConfigured("`%s.list_display['%d']`, `%s` is a " |
|---|
| 129 |
+ "ManyToManyField which is not supported." |
|---|
| 130 |
+ % (cls.__name__, idx, field)) |
|---|
| 131 |
+ |
|---|
| 132 |
+ # list_display_links |
|---|
| 133 |
+ if cls.list_display_links: |
|---|
| 134 |
+ _check_istuplew('list_display_links', cls.list_display_links) |
|---|
| 135 |
+ for idx, field in enumerate(cls.list_display_links): |
|---|
| 136 |
+ _check_attr_existsw('list_display_links[%d]' % idx, field) |
|---|
| 137 |
+ if field not in cls.list_display: |
|---|
| 138 |
+ raise ImproperlyConfigured("`%s.list_display_links['%d']`" |
|---|
| 139 |
+ "refers to `%s` which is not defined in `list_display`." |
|---|
| 140 |
+ % (cls.__name__, idx, field)) |
|---|
| 141 |
+ |
|---|
| 142 |
+ # list_filter |
|---|
| 143 |
+ if cls.list_filter: |
|---|
| 144 |
+ _check_istuplew('list_filter', cls.list_filter) |
|---|
| 145 |
+ for idx, field in enumerate(cls.list_filter): |
|---|
| 146 |
+ _check_field_existsw('list_filter[%d]' % idx, field) |
|---|
| 147 |
+ |
|---|
| 148 |
+ # list_per_page = 100 |
|---|
| 149 |
+ if not isinstance(cls.list_per_page, int): |
|---|
| 150 |
+ raise ImproperlyConfigured("`%s.list_per_page` should be a integer." |
|---|
| 151 |
+ % cls.__name__) |
|---|
| 152 |
+ |
|---|
| 153 |
+ # search_fields = () |
|---|
| 154 |
+ if cls.search_fields: |
|---|
| 155 |
+ _check_istuplew('search_fields', cls.search_fields) |
|---|
| 156 |
+ # TODO: search field validation is quite complex (restrictions, |
|---|
| 157 |
+ # follow fields etc), will skip it as of now |
|---|
| 158 |
+ # for idx, field in enumerate(cls.search_fields): |
|---|
| 159 |
+ # _check_field_existsw('search_fields[%d]' % idx, field) |
|---|
| 160 |
+ |
|---|
| 161 |
+ # date_hierarchy = None |
|---|
| 162 |
+ if cls.date_hierarchy: |
|---|
| 163 |
+ f = _check_field_existsw('date_hierarchy', cls.date_hierarchy) |
|---|
| 164 |
+ if not isinstance(f, (models.DateField, models.DateTimeField)): |
|---|
| 165 |
+ raise ImproperlyConfigured("`%s.date_hierarchy is " |
|---|
| 166 |
+ "neither an instance of DateField nor DateTimeField." |
|---|
| 167 |
+ % cls.__name__) |
|---|
| 168 |
+ |
|---|
| 169 |
+ # ordering = None |
|---|
| 170 |
+ if cls.ordering: |
|---|
| 171 |
+ _check_istuplew('ordering', cls.ordering) |
|---|
| 172 |
+ for idx, field in enumerate(cls.ordering): |
|---|
| 173 |
+ if field == '?' and len(cls.ordering) != 1: |
|---|
| 174 |
+ raise ImproperlyConfigured("`%s.ordering` has the random " |
|---|
| 175 |
+ "ordering marker `?`, but contains other fields as " |
|---|
| 176 |
+ "well. Please either remove `?` or the other fields." |
|---|
| 177 |
+ % cls.__name__) |
|---|
| 178 |
+ if field.startswith('-'): |
|---|
| 179 |
+ field = field[1:] |
|---|
| 180 |
+ _check_field_existsw('ordering[%d]' % idx, field) |
|---|
| 181 |
+ |
|---|
| 182 |
+ # list_select_related = False |
|---|
| 183 |
+ # save_as = False |
|---|
| 184 |
+ # save_on_top = False |
|---|
| 185 |
+ for attr in ('list_select_related', 'save_as', 'save_on_top'): |
|---|
| 186 |
+ if not isinstance(getattr(cls, attr), bool): |
|---|
| 187 |
+ raise ImproperlyConfigured("`%s.%s` should be a boolean." |
|---|
| 188 |
+ % (cls.__name__, attr)) |
|---|
| 189 |
+ |
|---|
| 190 |
+ # inlines = [] |
|---|
| 191 |
+ if cls.inlines: |
|---|
| 192 |
+ _check_istuplew('inlines', cls.inlines) |
|---|
| 193 |
+ for idx, inline in enumerate(cls.inlines): |
|---|
| 194 |
+ if not issubclass(inline, BaseModelAdmin): |
|---|
| 195 |
+ raise ImproperlyConfigured("`%s.inlines[%d]` does not inherit " |
|---|
| 196 |
+ "from BaseModelAdmin." % (cls.__name__, idx)) |
|---|
| 197 |
+ if not inline.model: |
|---|
| 198 |
+ raise ImproperlyConfigured("`model` is a required attribute " |
|---|
| 199 |
+ "of `%s.inlines[%d]`." % (cls.__name__, idx)) |
|---|
| 200 |
+ if not issubclass(inline.model, models.Model): |
|---|
| 201 |
+ raise ImproperlyConfigured("`%s.inlines[%d].model` does not " |
|---|
| 202 |
+ "inherit from models.Model." % (cls.__name__, idx)) |
|---|
| 203 |
+ _validate_base(inline, inline.model) |
|---|
| 204 |
+ _validate_inline(inline) |
|---|
| 205 |
+ |
|---|
| 206 |
+ # TODO: check that the templates exist if given |
|---|
| 207 |
+ # change_form_template = None |
|---|
| 208 |
+ # change_list_template = None |
|---|
| 209 |
+ # delete_confirmation_template = None |
|---|
| 210 |
+ # object_history_template = None |
|---|
| 211 |
+ |
|---|
| 212 |
+ # hook for custom validation |
|---|
| 213 |
+ _call_validation_hook(cls, model) |
|---|
| 214 |
+ |
|---|
| 215 |
+def _validate_inline(cls): |
|---|
| 216 |
+ # model is already verified to exist and be a Model |
|---|
| 217 |
+ if cls.fk_name: |
|---|
| 218 |
+ f = _check_field_exists(cls, cls.model, cls.model._meta, |
|---|
| 219 |
+ 'fk_name', cls.fk_name) |
|---|
| 220 |
+ if not isinstance(f, models.ForeignKey): |
|---|
| 221 |
+ raise ImproperlyConfigured("`%s.fk_name is not an instance of " |
|---|
| 222 |
+ "models.ForeignKey." % cls.__name__) |
|---|
| 223 |
+ # extra = 3 |
|---|
| 224 |
+ # max_num = 0 |
|---|
| 225 |
+ for attr in ('extra', 'max_num'): |
|---|
| 226 |
+ if not isinstance(getattr(cls, attr), int): |
|---|
| 227 |
+ raise ImproperlyConfigured("`%s.%s` should be a integer." |
|---|
| 228 |
+ % (cls.__name__, attr)) |
|---|
| 229 |
+ |
|---|
| 230 |
+ #TODO: check the following |
|---|
| 231 |
+ # formset = BaseInlineFormset |
|---|
| 232 |
+ # template = None |
|---|
| 233 |
+ # verbose_name = None |
|---|
| 234 |
+ # verbose_name_plural = None |
|---|
| 235 |
+ |
|---|
| 236 |
+ # hook for custom validation |
|---|
| 237 |
+ _call_validation_hook(cls, cls.model) |
|---|
| 238 |
+ |
|---|
| 239 |
+def _validate_base(cls, model): |
|---|
| 240 |
+ opts = model._meta |
|---|
| 241 |
+ # currying is expensive, use wrappers instead |
|---|
| 242 |
+ def _check_istuplew(label, obj): |
|---|
| 243 |
+ _check_istuple(cls, label, obj) |
|---|
| 244 |
+ |
|---|
| 245 |
+ def _check_isdictw(label, obj): |
|---|
| 246 |
+ _check_isdict(cls, label, obj) |
|---|
| 247 |
+ |
|---|
| 248 |
+ def _check_field_existsw(label, field): |
|---|
| 249 |
+ return _check_field_exists(cls, model, opts, label, field) |
|---|
| 250 |
+ |
|---|
| 251 |
+ # raw_id_fields |
|---|
| 252 |
+ if cls.raw_id_fields: |
|---|
| 253 |
+ _check_istuplew('raw_id_fields', cls.raw_id_fields) |
|---|
| 254 |
+ for field in cls.raw_id_fields: |
|---|
| 255 |
+ _check_field_existsw('raw_id_fields', field) |
|---|
| 256 |
+ |
|---|
| 257 |
+ # fields |
|---|
| 258 |
+ if cls.fields: |
|---|
| 259 |
+ for field in cls.fields: |
|---|
| 260 |
+ _check_field_existsw('fields', field) |
|---|
| 261 |
+ |
|---|
| 262 |
+ # fieldsets |
|---|
| 263 |
+ if cls.fieldsets: |
|---|
| 264 |
+ _check_istuplew('fieldsets', cls.fieldsets) |
|---|
| 265 |
+ for idx, fieldset in enumerate(cls.fieldsets): |
|---|
| 266 |
+ _check_istuplew('fieldsets[%d]' % idx, fieldset) |
|---|
| 267 |
+ if len(fieldset) != 2: |
|---|
| 268 |
+ raise ImproperlyConfigured("`%s.fieldsets[%d]` does not " |
|---|
| 269 |
+ "have exactly two elements." % (cls.__name__, idx)) |
|---|
| 270 |
+ _check_isdictw('fieldsets[%d][1]' % idx, fieldset[1]) |
|---|
| 271 |
+ if 'fields' not in fieldset[1]: |
|---|
| 272 |
+ raise ImproperlyConfigured("`fields` key is required in " |
|---|
| 273 |
+ "%s.fieldsets[%d][1] field options dict." |
|---|
| 274 |
+ % (cls.__name__, idx)) |
|---|
| 275 |
+ for field in flatten_fieldsets(cls.fieldsets): |
|---|
| 276 |
+ _check_field_existsw("fieldsets[%d][1]['fields']" % idx, field) |
|---|
| 277 |
+ |
|---|
| 278 |
+ # form FIXME: brosner, is this correct? |
|---|
| 279 |
+ # if cls.form and not isinstance(cls.form, forms.BaseForm): |
|---|
| 280 |
+ # raise ImproperlyConfigured("%s.form is not a form instance." |
|---|
| 281 |
+ # % cls.__name__) |
|---|
| 282 |
+ |
|---|
| 283 |
+ # filter_vertical |
|---|
| 284 |
+ if cls.filter_vertical: |
|---|
| 285 |
+ _check_istuplew('filter_vertical', cls.filter_vertical) |
|---|
| 286 |
+ for field in cls.filter_vertical: |
|---|
| 287 |
+ _check_field_existsw('filter_vertical', field) |
|---|
| 288 |
+ |
|---|
| 289 |
+ # filter_horizontal |
|---|
| 290 |
+ if cls.filter_horizontal: |
|---|
| 291 |
+ _check_istuplew('filter_horizontal', cls.filter_horizontal) |
|---|
| 292 |
+ for field in cls.filter_horizontal: |
|---|
| 293 |
+ _check_field_existsw('filter_horizontal', field) |
|---|
| 294 |
+ |
|---|
| 295 |
+ # radio_fields |
|---|
| 296 |
+ if cls.radio_fields: |
|---|
| 297 |
+ _check_isdictw('radio_fields', cls.radio_fields) |
|---|
| 298 |
+ for field, val in cls.radio_fields.items(): |
|---|
| 299 |
+ f = _check_field_existsw('radio_fields', field) |
|---|
| 300 |
+ if not (isinstance(f, models.ForeignKey) or f.choices): |
|---|
| 301 |
+ raise ImproperlyConfigured("`%s.radio_fields['%s']` " |
|---|
| 302 |
+ "is neither an instance of ForeignKey nor does " |
|---|
| 303 |
+ "have choices set." % (cls.__name__, field)) |
|---|
| 304 |
+ if not val in (HORIZONTAL, VERTICAL): |
|---|
| 305 |
+ raise ImproperlyConfigured("`%s.radio_fields['%s']` " |
|---|
| 306 |
+ "is neither admin.HORIZONTAL nor admin.VERTICAL." |
|---|
| 307 |
+ % (cls.__name__, field)) |
|---|
| 308 |
+ |
|---|
| 309 |
+ # prepopulated_fields |
|---|
| 310 |
+ if cls.prepopulated_fields: |
|---|
| 311 |
+ _check_isdictw('prepopulated_fields', cls.prepopulated_fields) |
|---|
| 312 |
+ for field, val in cls.prepopulated_fields.items(): |
|---|
| 313 |
+ f = _check_field_existsw('prepopulated_fields', field) |
|---|
| 314 |
+ if isinstance(f, (models.DateTimeField, models.ForeignKey, |
|---|
| 315 |
+ models.ManyToManyField)): |
|---|
| 316 |
+ raise ImproperlyConfigured("`%s.prepopulated_fields['%s']` " |
|---|
| 317 |
+ "is either a DateTimeField, ForeignKey or " |
|---|
| 318 |
+ "ManyToManyField. This isn't allowed." |
|---|
| 319 |
+ % (cls.__name__, field)) |
|---|
| 320 |
+ _check_istuplew("prepopulated_fields['%s']" % field, val) |
|---|
| 321 |
+ for idx, f in enumerate(val): |
|---|
| 322 |
+ _check_field_existsw("prepopulated_fields['%s'][%d]" |
|---|
| 323 |
+ % (f, idx), f) |
|---|
| 324 |
+ |
|---|
| 325 |
+def _call_validation_hook(cls, model): |
|---|
| 326 |
+ if hasattr(cls, 'validate'): |
|---|
| 327 |
+ if not callable(cls.validate): |
|---|
| 328 |
+ raise ImproperlyConfigured("`%s.validate` should be a callable " |
|---|
| 329 |
+ "(class method)." % cls.__name__) |
|---|
| 330 |
+ cls.validate(model) |
|---|
| 331 |
+ |
|---|
| 332 |
+def _check_istuple(cls, label, obj): |
|---|
| 333 |
+ if not isinstance(obj, (list, tuple)): |
|---|
| 334 |
+ raise ImproperlyConfigured("`%s.%s` must be a " |
|---|
| 335 |
+ "list or tuple." % (cls.__name__, label)) |
|---|
| 336 |
+ |
|---|
| 337 |
+def _check_isdict(cls, label, obj): |
|---|
| 338 |
+ if not isinstance(obj, dict): |
|---|
| 339 |
+ raise ImproperlyConfigured("`%s.%s` must be a dictionary." |
|---|
| 340 |
+ % (cls.__name__, label)) |
|---|
| 341 |
+ |
|---|
| 342 |
+def _check_field_exists(cls, model, opts, label, field): |
|---|
| 343 |
+ try: |
|---|
| 344 |
+ return opts.get_field(field) |
|---|
| 345 |
+ except models.FieldDoesNotExist: |
|---|
| 346 |
+ raise ImproperlyConfigured("`%s.%s` refers to " |
|---|
| 347 |
+ "field `%s` that is missing from model `%s`." |
|---|
| 348 |
+ % (cls.__name__, label, field, model.__name__)) |
|---|
| 349 |
+ |
|---|
| 350 |
+def _check_attr_exists(cls, model, opts, label, field): |
|---|
| 351 |
+ try: |
|---|
| 352 |
+ return opts.get_field(field) |
|---|
| 353 |
+ except models.FieldDoesNotExist: |
|---|
| 354 |
+ if not hasattr(model, field): |
|---|
| 355 |
+ raise ImproperlyConfigured("`%s.%s` refers to " |
|---|
| 356 |
+ "`%s` that is neither a field, method or property " |
|---|
| 357 |
+ "of model `%s`." |
|---|
| 358 |
+ % (cls.__name__, label, field, model.__name__)) |
|---|
| 359 |
+ return getattr(model, field) |
|---|
| 360 |
Index: django/contrib/admin/sites.py |
|---|
| 361 |
=================================================================== |
|---|
| 362 |
--- django/contrib/admin/sites.py (revision 7884) |
|---|
| 363 |
+++ django/contrib/admin/sites.py (working copy) |
|---|
| 364 |
@@ -7,6 +7,7 @@ |
|---|
| 365 |
from django.utils.text import capfirst |
|---|
| 366 |
from django.utils.translation import ugettext_lazy, ugettext as _ |
|---|
| 367 |
from django.views.decorators.cache import never_cache |
|---|
| 368 |
+from django.conf import settings |
|---|
| 369 |
import base64 |
|---|
| 370 |
import cPickle as pickle |
|---|
| 371 |
import datetime |
|---|
| 372 |
@@ -65,6 +66,10 @@ |
|---|
| 373 |
|
|---|
| 374 |
If a model is already registered, this will raise AlreadyRegistered. |
|---|
| 375 |
""" |
|---|
| 376 |
+ do_validate = admin_class and settings.DEBUG |
|---|
| 377 |
+ if do_validate: |
|---|
| 378 |
+ # don't import the humongous validation code unless necessary |
|---|
| 379 |
+ from django.contrib.admin.validation import validate |
|---|
| 380 |
admin_class = admin_class or ModelAdmin |
|---|
| 381 |
# TODO: Handle options |
|---|
| 382 |
if isinstance(model_or_iterable, ModelBase): |
|---|
| 383 |
@@ -72,6 +77,8 @@ |
|---|
| 384 |
for model in model_or_iterable: |
|---|
| 385 |
if model in self._registry: |
|---|
| 386 |
raise AlreadyRegistered('The model %s is already registered' % model.__name__) |
|---|
| 387 |
+ if do_validate: |
|---|
| 388 |
+ validate(admin_class, model) |
|---|
| 389 |
self._registry[model] = admin_class(model, self) |
|---|
| 390 |
|
|---|
| 391 |
def unregister(self, model_or_iterable): |
|---|