From 8f9e5b6b3ba7165ddac717690d9710b49a4a5a6a Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Mon, 15 Aug 2005 05:05:52 +0000 Subject: [PATCH] Added 'django-admin.py validate', which validates all installed models. Validation only handles common errors at this point, but we'll be improving it each time we think of a potential model syntax problem. Also changed the development Web server to validate automatically at server start. git-svn-id: http://code.djangoproject.com/svn/django/trunk@503 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/bin/django-admin.py | 7 +++-- django/core/management.py | 56 +++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/django/bin/django-admin.py b/django/bin/django-admin.py index fc9ffec373..c4aa51a066 100755 --- a/django/bin/django-admin.py +++ b/django/bin/django-admin.py @@ -7,7 +7,9 @@ ACTION_MAPPING = { 'adminindex': management.get_admin_index, 'createsuperuser': management.createsuperuser, # 'dbcheck': management.database_check, + 'init': management.init, 'inspectdb': management.inspectdb, + 'install': management.install, 'runserver': management.runserver, 'sql': management.get_sql_create, 'sqlall': management.get_sql_all, @@ -18,8 +20,7 @@ ACTION_MAPPING = { 'sqlsequencereset': management.get_sql_sequence_reset, 'startapp': management.startapp, 'startproject': management.startproject, - 'init': management.init, - 'install': management.install, + 'validate': management.validate, } NO_SQL_TRANSACTION = ('adminindex', 'dbcheck', 'install', 'sqlindexes') @@ -65,7 +66,7 @@ def main(): print_error("An action is required.", sys.argv[0]) if not ACTION_MAPPING.has_key(action): print_error("Your action, %r, was invalid." % action, sys.argv[0]) - if action in ('createsuperuser', 'init'): + if action in ('createsuperuser', 'init', 'validate'): ACTION_MAPPING[action]() elif action == 'inspectdb': try: diff --git a/django/core/management.py b/django/core/management.py index 6ce06e7182..07ea6671e8 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -483,6 +483,58 @@ def inspectdb(db_name): inspectdb.help_doc = "Introspects the database tables in the given database and outputs a Django model module." inspectdb.args = "[dbname]" +class ModelErrorCollection: + def __init__(self, outfile=sys.stdout): + self.errors = [] + self.outfile = outfile + + def add(self, opts, error): + self.errors.append((opts, error)) + self.outfile.write("%s.%s: %s\n" % (opts.module_name, opts.object_name, error)) + +def validate(): + "Validates all installed models." + from django.core import meta + e = ModelErrorCollection() + module_list = meta.get_installed_model_modules() + for module in module_list: + for mod in module._MODELS: + opts = mod._meta + + # Do field-specific validation. + for f in opts.fields: + if isinstance(f, meta.CharField) and f.maxlength in (None, 0): + e.add(opts, '"%s" field: CharFields require a "maxlength" attribute.' % f.name) + + # Check admin attribute. + if opts.admin is not None and not isinstance(opts.admin, meta.Admin): + e.add(opts, '"admin" attribute, if given, must be set to a meta.Admin() instance.') + + # Check ordering attribute. + if opts.ordering: + for field_name in opts.ordering: + if field_name == '?': continue + if field_name.startswith('-'): + field_name = field_name[1:] + try: + opts.get_field(field_name, many_to_many=False) + except meta.FieldDoesNotExist: + e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name) + + # Check core=True, if needed. + for rel_opts, rel_field in opts.get_inline_related_objects(): + try: + for f in rel_opts.fields: + if f.core: + raise StopIteration + e.add(rel_opts, "At least one field in %s should have core=True, because it's being edited inline by %s.%s." % (rel_opts.object_name, opts.module_name, opts.object_name)) + except StopIteration: + pass + + num_errors = len(e.errors) + print '%s error%s found.' % (num_errors, num_errors != 1 and 's' or '') +validate.args = '' + def runserver(port): "Starts a lightweight Web server for development." from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException @@ -492,7 +544,9 @@ def runserver(port): sys.exit(1) def inner_run(): from django.conf.settings import SETTINGS_MODULE - print "Starting server on port %s with settings module %r." % (port, SETTINGS_MODULE) + print "Validating models..." + validate() + print "\nStarting server on port %s with settings module %r." % (port, SETTINGS_MODULE) print "Go to http://127.0.0.1:%s/ for Django." % port print "Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows)." try: