Django

Code

root/django/branches/schema-evolution/django/core/management.py

Revision 5822, 86.6 kB (checked in by danderson, 2 years ago)

schema-evolution: update from HEAD (v5821)

Line 
1 # Django management-related functions, including "CREATE TABLE" generation and
2 # development-server initialization.
3
4 import django
5 from django.core.exceptions import ImproperlyConfigured
6 from optparse import OptionParser
7 from django.utils import termcolors
8 from django.conf import settings
9 import os, re, shutil, sys, textwrap
10
11 try:
12     set
13 except NameError:
14     from sets import Set as set   # Python 2.3 fallback
15
16 # For backwards compatibility: get_version() used to be in this module.
17 get_version = django.get_version
18
19 MODULE_TEMPLATE = '''    {%% if perms.%(app)s.%(addperm)s or perms.%(app)s.%(changeperm)s %%}
20     <tr>
21         <th>{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/">{%% endif %%}%(name)s{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</th>
22         <td class="x50">{%% if perms.%(app)s.%(addperm)s %%}<a href="%(app)s/%(mod)s/add/" class="addlink">{%% endif %%}Add{%% if perms.%(app)s.%(addperm)s %%}</a>{%% endif %%}</td>
23         <td class="x75">{%% if perms.%(app)s.%(changeperm)s %%}<a href="%(app)s/%(mod)s/" class="changelink">{%% endif %%}Change{%% if perms.%(app)s.%(changeperm)s %%}</a>{%% endif %%}</td>
24     </tr>
25     {%% endif %%}'''
26
27 APP_ARGS = '[appname ...]'
28
29 # Use django.__path__[0] because we don't know which directory django into
30 # which has been installed.
31 PROJECT_TEMPLATE_DIR = os.path.join(django.__path__[0], 'conf', '%s_template')
32
33 INVALID_PROJECT_NAMES = ('django', 'site', 'test')
34
35 # Set up the terminal color scheme.
36 class dummy: pass
37 style = dummy()
38 style.ERROR = termcolors.make_style(fg='red', opts=('bold',))
39 style.ERROR_OUTPUT = termcolors.make_style(fg='red', opts=('bold',))
40 style.NOTICE = termcolors.make_style(fg='red')
41 style.SQL_FIELD = termcolors.make_style(fg='green', opts=('bold',))
42 style.SQL_COLTYPE = termcolors.make_style(fg='green')
43 style.SQL_KEYWORD = termcolors.make_style(fg='yellow')
44 style.SQL_TABLE = termcolors.make_style(opts=('bold',))
45 del dummy
46
47 def disable_termcolors():
48     class dummy:
49         def __getattr__(self, attr):
50             return lambda x: x
51     global style
52     style = dummy()
53
54 # Disable terminal coloring on Windows, Pocket PC, or if somebody's piping the output.
55 if sys.platform == 'win32' or sys.platform == 'Pocket PC' or not sys.stdout.isatty():
56     disable_termcolors()
57
58 def _is_valid_dir_name(s):
59     return bool(re.search(r'^\w+$', s))
60
61 def _get_installed_models(table_list):
62     "Gets a set of all models that are installed, given a list of existing tables"
63     from django.db import backend, models
64     all_models = []
65     for app in models.get_apps():
66         for model in models.get_models(app):
67             all_models.append(model)
68     if backend.uses_case_insensitive_names:
69         converter = str.upper
70     else:
71         converter = lambda x: x
72     return set([m for m in all_models if converter(m._meta.db_table) in map(converter, table_list)])
73
74 def _get_table_list():
75     "Gets a list of all db tables that are physically installed."
76     from django.db import connection, get_introspection_module
77     cursor = connection.cursor()
78     return get_introspection_module().get_table_list(cursor)
79
80 def _get_sequence_list():
81     "Returns a list of information about all DB sequences for all models in all apps"
82     from django.db import models
83
84     apps = models.get_apps()
85     sequence_list = []
86
87     for app in apps:
88         for model in models.get_models(app):
89             for f in model._meta.fields:
90                 if isinstance(f, models.AutoField):
91                     sequence_list.append({'table':model._meta.db_table,'column':f.column,})
92                     break # Only one AutoField is allowed per model, so don't bother continuing.
93
94             for f in model._meta.many_to_many:
95                 sequence_list.append({'table':f.m2m_db_table(),'column':None,})
96
97     return sequence_list
98
99 def get_sql_create(app):
100     "Returns a list of the CREATE TABLE SQL statements for the given app."
101     from django.db import models
102     from django.conf import settings
103
104     if settings.DATABASE_ENGINE == 'dummy':
105         # This must be the "dummy" database backend, which means the user
106         # hasn't set DATABASE_ENGINE.
107         sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
108             "because you haven't specified the DATABASE_ENGINE setting.\n" +
109             "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
110         sys.exit(1)
111
112     # Get installed models, so we generate REFERENCES right.
113     # We trim models from the current app so that the sqlreset command does not
114     # generate invalid SQL (leaving models out of known_models is harmless, so
115     # we can be conservative).
116     app_models = models.get_models(app)
117     final_output = []
118     known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models])
119     pending_references = {}
120
121     for model in app_models:
122         output, references = _get_sql_model_create(model, known_models)
123         final_output.extend(output)
124         for refto, refs in references.items():
125             pending_references.setdefault(refto,[]).extend(refs)
126         final_output.extend(_get_sql_for_pending_references(model, pending_references))
127         # Keep track of the fact that we've created the table for this model.
128         known_models.add(model)
129
130     # Create the many-to-many join tables.
131     for model in app_models:
132         final_output.extend(_get_many_to_many_sql_for_model(model))
133
134     # Handle references to tables that are from other apps
135     # but don't exist physically
136     not_installed_models = set(pending_references.keys())
137     if not_installed_models:
138         alter_sql = []
139         for model in not_installed_models:
140             alter_sql.extend(['-- ' + sql for sql in
141                 _get_sql_for_pending_references(model, pending_references)])
142         if alter_sql:
143             final_output.append('-- The following references should be added but depend on non-existent tables:')
144             final_output.extend(alter_sql)
145
146     return final_output
147 get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)."
148 get_sql_create.args = APP_ARGS
149
150 def _get_sql_model_create(model, known_models=set()):
151     """
152     Get the SQL required to create a single model.
153
154     Returns list_of_sql, pending_references_dict
155     """
156     from django.db import backend, models
157
158     opts = model._meta
159     final_output = []
160     table_output = []
161     pending_references = {}
162     for f in opts.fields:
163         col_type = f.db_type()
164         tablespace = f.db_tablespace or opts.db_tablespace
165         if col_type is None:
166             # Skip ManyToManyFields, because they're not represented as
167             # database columns in this table.
168             continue
169         # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
170         field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
171             style.SQL_COLTYPE(col_type)]
172         field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
173         if (f.unique and (not f.primary_key or backend.allows_unique_and_pk)) or (f.primary_key and backend.pk_requires_unique):
174             field_output.append(style.SQL_KEYWORD('UNIQUE'))
175         if f.primary_key:
176             field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
177         if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
178             # We must specify the index tablespace inline, because we
179             # won't be generating a CREATE INDEX statement for this field.
180             field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
181         if f.rel:
182             if f.rel.to in known_models:
183                 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
184                     style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
185                     style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
186                     backend.get_deferrable_sql()
187                 )
188             else:
189                 # We haven't yet created the table to which this field
190                 # is related, so save it for later.
191                 pr = pending_references.setdefault(f.rel.to, []).append((model, f))
192         table_output.append(' '.join(field_output))
193     if opts.order_with_respect_to:
194         table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
195             style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
196             style.SQL_KEYWORD('NULL'))
197     for field_constraints in opts.unique_together:
198         table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
199             ", ".join([backend.quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
200
201     full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
202     for i, line in enumerate(table_output): # Combine and add commas.
203         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
204     full_statement.append(')')
205     if opts.db_tablespace and backend.supports_tablespaces:
206         full_statement.append(backend.get_tablespace_sql(opts.db_tablespace))
207     full_statement.append(';')
208     final_output.append('\n'.join(full_statement))
209
210     if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'):
211         # Add any extra SQL needed to support auto-incrementing primary keys
212         autoinc_sql = backend.get_autoinc_sql(opts.db_table)
213         if autoinc_sql:
214             for stmt in autoinc_sql:
215                 final_output.append(stmt)
216
217     return final_output, pending_references
218
219 def _get_sql_for_pending_references(model, pending_references):
220     """
221     Get any ALTER TABLE statements to add constraints after the fact.
222     """
223     from django.db import backend
224     from django.db.backends.util import truncate_name
225
226     final_output = []
227     if backend.supports_constraints:
228         opts = model._meta
229         if model in pending_references:
230             for rel_class, f in pending_references[model]:
231                 rel_opts = rel_class._meta
232                 r_table = rel_opts.db_table
233                 r_col = f.column
234                 table = opts.db_table
235                 col = opts.get_field(f.rel.field_name).column
236                 # For MySQL, r_name must be unique in the first 64 characters.
237                 # So we are careful with character usage here.
238                 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
239                 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
240                     (backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
241                     backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
242                     backend.get_deferrable_sql()))
243             del pending_references[model]
244     return final_output
245
246 def _get_many_to_many_sql_for_model(model):
247     from django.db import backend, models
248     from django.contrib.contenttypes import generic
249
250     opts = model._meta
251     final_output = []
252     for f in opts.many_to_many:
253         if not isinstance(f.rel, generic.GenericRel):
254             tablespace = f.db_tablespace or opts.db_tablespace
255             if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
256                 tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)
257             else:
258                 tablespace_sql = ''
259             table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
260                 style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
261             table_output.append('    %s %s %s%s,' % \
262                 (style.SQL_FIELD(backend.quote_name('id')),
263                 style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
264                 style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
265                 tablespace_sql))
266             table_output.append('    %s %s %s %s (%s)%s,' % \
267                 (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
268                 style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
269                 style.SQL_KEYWORD('NOT NULL REFERENCES'),
270                 style.SQL_TABLE(backend.quote_name(opts.db_table)),
271                 style.SQL_FIELD(backend.quote_name(opts.pk.column)),
272                 backend.get_deferrable_sql()))
273             table_output.append('    %s %s %s %s (%s)%s,' % \
274                 (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
275                 style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
276                 style.SQL_KEYWORD('NOT NULL REFERENCES'),
277                 style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
278                 style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
279                 backend.get_deferrable_sql()))
280             table_output.append('    %s (%s, %s)%s' % \
281                 (style.SQL_KEYWORD('UNIQUE'),
282                 style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
283                 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
284                 tablespace_sql))
285             table_output.append(')')
286             if opts.db_tablespace and backend.supports_tablespaces:
287                 # f.db_tablespace is only for indices, so ignore its value here.
288                 table_output.append(backend.get_tablespace_sql(opts.db_tablespace))
289             table_output.append(';')
290             final_output.append('\n'.join(table_output))
291
292             # Add any extra SQL needed to support auto-incrementing PKs
293             autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table())
294             if autoinc_sql:
295                 for stmt in autoinc_sql:
296                     final_output.append(stmt)
297
298     return final_output
299
300 def get_sql_delete(app):
301     "Returns a list of the DROP TABLE SQL statements for the given app."
302     from django.db import backend, connection, models, get_introspection_module
303     from django.db.backends.util import truncate_name
304     introspection = get_introspection_module()
305
306     # This should work even if a connection isn't available
307     try:
308         cursor = connection.cursor()
309     except:
310         cursor = None
311
312     # Figure out which tables already exist
313     if cursor:
314         table_names = introspection.get_table_list(cursor)
315     else:
316         table_names = []
317     if backend.uses_case_insensitive_names:
318         table_name_converter = str.upper
319     else:
320         table_name_converter = lambda x: x
321
322     output = []
323
324     # Output DROP TABLE statements for standard application tables.
325     to_delete = set()
326
327     references_to_delete = {}
328     app_models = models.get_models(app)
329     for model in app_models:
330         if cursor and table_name_converter(model._meta.db_table) in table_names:
331             # The table exists, so it needs to be dropped
332             opts = model._meta
333             for f in opts.fields:
334                 if f.rel and f.rel.to not in to_delete:
335                     references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
336
337             to_delete.add(model)
338
339     for model in app_models:
340         if cursor and table_name_converter(model._meta.db_table) in table_names:
341             # Drop the table now
342             output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
343                 style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
344             if backend.supports_constraints and model in references_to_delete:
345                 for rel_class, f in references_to_delete[model]:
346                     table = rel_class._meta.db_table
347                     col = f.column
348                     r_table = model._meta.db_table
349                     r_col = model._meta.get_field(f.rel.field_name).column
350                     r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
351                     output.append('%s %s %s %s;' % \
352                         (style.SQL_KEYWORD('ALTER TABLE'),
353                         style.SQL_TABLE(backend.quote_name(table)),
354                         style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
355                         style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
356                 del references_to_delete[model]
357             if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'):
358                 output.append(backend.get_drop_sequence(model._meta.db_table))
359
360     # Output DROP TABLE statements for many-to-many tables.
361     for model in app_models:
362         opts = model._meta
363         for f in opts.many_to_many:
364             if cursor and table_name_converter(f.m2m_db_table()) in table_names:
365                 output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
366                     style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
367                 if hasattr(backend, 'get_drop_sequence'):
368                     output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
369
370
371     app_label = app_models[0]._meta.app_label
372
373     # Close database connection explicitly, in case this output is being piped
374     # directly into a database client, to avoid locking issues.
375     if cursor:
376         cursor.close()
377         connection.close()
378
379     return output[::-1] # Reverse it, to deal with table dependencies.
380 get_sql_delete.help_doc = "Prints the DROP TABLE SQL statements for the given app name(s)."
381 get_sql_delete.args = APP_ARGS
382
383 def get_sql_reset(app):
384     "Returns a list of the DROP TABLE SQL, then the CREATE TABLE SQL, for the given module."
385     return get_sql_delete(app) + get_sql_all(app)
386 get_sql_reset.help_doc = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
387 get_sql_reset.args = APP_ARGS
388
389 def get_sql_flush():
390     "Returns a list of the SQL statements used to flush the database"
391     from django.db import backend
392     statements = backend.get_sql_flush(style, _get_table_list(), _get_sequence_list())
393     return statements
394 get_sql_flush.help_doc = "Returns a list of the SQL statements required to return all tables in the database to the state they were in just after they were installed."
395 get_sql_flush.args = ''
396
397 def get_custom_sql_for_model(model):
398     from django.db import models
399     from django.conf import settings
400
401     opts = model._meta
402     app_dir = os.path.normpath(os.path.join(os.path.dirname(models.get_app(model._meta.app_label).__file__), 'sql'))
403     output = []
404
405     # Some backends can't execute more than one SQL statement at a time,
406     # so split into separate statements.
407     statements = re.compile(r";[ \t]*$", re.M)
408
409     # Find custom SQL, if it's available.
410     sql_files = [os.path.join(app_dir, "%s.%s.sql" % (opts.object_name.lower(), settings.DATABASE_ENGINE)),
411                  os.path.join(app_dir, "%s.sql" % opts.object_name.lower())]
412     for sql_file in sql_files:
413         if os.path.exists(sql_file):
414             fp = open(sql_file, 'U')
415             for statement in statements.split(fp.read().decode(settings.FILE_CHARSET)):
416                 # Remove any comments from the file
417                 statement = re.sub(ur"--.*[\n\Z]", "", statement)
418                 if statement.strip():
419                     output.append(statement + u";")
420             fp.close()
421
422     return output
423
424 def get_custom_sql(app):
425     "Returns a list of the custom table modifying SQL statements for the given app."
426     from django.db.models import get_models
427     output = []
428
429     app_models = get_models(app)
430     app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
431
432     for model in app_models:
433         output.extend(get_custom_sql_for_model(model))
434
435     return output
436 get_custom_sql.help_doc = "Prints the custom table modifying SQL statements for the given app name(s)."
437 get_custom_sql.args = APP_ARGS
438
439 def get_sql_initial_data(apps):
440     "Returns a list of the initial INSERT SQL statements for the given app."
441     return style.ERROR("This action has been renamed. Try './manage.py sqlcustom %s'." % ' '.join(apps and apps or ['app1', 'app2']))
442 get_sql_initial_data.help_doc = "RENAMED: see 'sqlcustom'"
443 get_sql_initial_data.args = ''
444
445 def get_sql_sequence_reset(app):
446     "Returns a list of the SQL statements to reset sequences for the given app."
447     from django.db import backend, models
448     return backend.get_sql_sequence_reset(style, models.get_models(app))
449 get_sql_sequence_reset.help_doc = "Prints the SQL statements for resetting sequences for the given app name(s)."
450 get_sql_sequence_reset.args = APP_ARGS
451
452 def get_sql_indexes(app):
453     "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
454     from django.db import models
455     output = []
456     for model in models.get_models(app):
457         output.extend(get_sql_indexes_for_model(model))
458     return output
459 get_sql_indexes.help_doc = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
460 get_sql_indexes.args = APP_ARGS
461
462 def get_sql_indexes_for_model(model):
463     "Returns the CREATE INDEX SQL statements for a single model"
464     from django.db import backend
465     output = []
466
467     for f in model._meta.fields:
468         if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
469             unique = f.unique and 'UNIQUE ' or ''
470             tablespace = f.db_tablespace or model._meta.db_tablespace
471             if tablespace and backend.supports_tablespaces:
472                 tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace)
473             else:
474                 tablespace_sql = ''
475             output.append(
476                 style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
477                 style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
478                 style.SQL_KEYWORD('ON') + ' ' + \
479                 style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
480                 "(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \
481                 "%s;" % tablespace_sql
482             )
483     return output
484    
485 def get_sql_fingerprint(app):
486     "Returns the fingerprint of the current schema, used in schema evolution."
487     from django.db import get_creation_module, models, backend, get_introspection_module, connection
488     # This should work even if a connecton isn't available
489     try:
490         cursor = connection.cursor()
491     except:
492         cursor = None
493     introspection = get_introspection_module()
494     app_name = app.__name__.split('.')[-2]
495     schema_fingerprint = introspection.get_schema_fingerprint(cursor, app)
496     try:
497         # is this a schema we recognize?
498         app_se = __import__(app_name +'.schema_evolution').schema_evolution
499         schema_recognized = schema_fingerprint in app_se.fingerprints
500         if schema_recognized:
501             sys.stderr.write(style.NOTICE("Notice: Current schema fingerprint for '%s' is '%s' (recognized)\n" % (app_name, schema_fingerprint)))
502         else:
503             sys.stderr.write(style.NOTICE("Notice: Current schema fingerprint for '%s' is '%s' (unrecognized)\n" % (app_name, schema_fingerprint)))
504     except:
505         sys.stderr.write(style.NOTICE("Notice: Current schema fingerprint for '%s' is '%s' (no schema_evolution module found)\n" % (app_name, schema_fingerprint)))
506     return
507 get_sql_fingerprint.help_doc = "Returns the fingerprint of the current schema, used in schema evolution."
508 get_sql_fingerprint.args = APP_ARGS
509
510 def get_sql_evolution(app):
511     "Returns SQL to update an existing schema to match the existing models."
512     return get_sql_evolution_detailed(app)[2]
513
514 def get_sql_evolution_detailed(app):
515     "Returns SQL to update an existing schema to match the existing models."
516     import schema_evolution
517     from django.db import get_creation_module, models, backend, get_introspection_module, connection
518     data_types = get_creation_module().DATA_TYPES
519
520     if not data_types:
521         # This must be the "dummy" database backend, which means the user
522         # hasn't set DATABASE_ENGINE.
523         sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements,\n" +
524             "because you haven't specified the DATABASE_ENGINE setting.\n" +
525             "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n"))
526         sys.exit(1)
527
528     try:
529         backend.get_add_column_sql
530     except:
531         # This must be an unsupported database backend
532         sys.stderr.write(style.ERROR("Error: Django doesn't know which syntax to use for your SQL statements, " +
533             "because schema evolution support isn't built into your database backend yet.  Sorry!\n"))
534         sys.exit(1)
535
536     # First, try validating the models.
537     _check_for_validation_errors()
538
539     # This should work even if a connecton isn't available
540     try:
541         cursor = connection.cursor()
542     except:
543         cursor = None
544
545     introspection = get_introspection_module()
546     app_name = app.__name__.split('.')[-2]
547
548     final_output = []
549
550     schema_fingerprint = introspection.get_schema_fingerprint(cursor, app)
551     try:
552         # is this a schema we recognize?
553         app_se = __import__(app_name +'.schema_evolution').schema_evolution
554         schema_recognized = schema_fingerprint in app_se.fingerprints
555         if schema_recognized:
556             sys.stderr.write(style.NOTICE("Notice: Current schema fingerprint for '%s' is '%s' (recognized)\n" % (app_name, schema_fingerprint)))
557             available_upgrades = []
558             for (vfrom, vto), upgrade in app_se.evolutions.iteritems():
559                 if vfrom == schema_fingerprint:
560                     try:
561                         distance = app_se.fingerprints.index(vto)-app_se.fingerprints.index(vfrom)
562                         available_upgrades.append( ( vfrom, vto, upgrade, distance ) )
563                         sys.stderr.write(style.NOTICE("\tan upgrade from %s to %s is available (distance: %i)\n" % ( vfrom, vto, distance )))
564                     except:
565                         available_upgrades.append( ( vfrom, vto, upgrade, -1 ) )
566                         sys.stderr.write(style.NOTICE("\tan upgrade from %s to %s is available, but %s is not in schema_evolution.fingerprints\n" % ( vfrom, vto, vto )))
567             if len(available_upgrades):
568                 best_upgrade = available_upgrades[0]
569                 for an_upgrade in available_upgrades:
570                     if an_upgrade[3] > best_upgrade[3]:
571                         best_upgrade = an_upgrade
572                 final_output.extend( best_upgrade[2] )
573                 return schema_fingerprint, False, final_output
574         else:
575             sys.stderr.write(style.NOTICE("Notice: Current schema fingerprint for '%s' is '%s' (unrecognized)\n" % (app_name, schema_fingerprint)))
576     except:
577         # sys.stderr.write(style.NOTICE("Notice: Current schema fingerprint for '%s' is '%s' (no schema_evolution module found)\n" % (app_name, schema_fingerprint)))
578         pass # ^^^ lets not be chatty
579
580     # stolen and trimmed from syncdb so that we know which models are about
581     # to be created (so we don't check them for updates)
582     table_list = _get_table_list()
583     seen_models = _get_installed_models(table_list)
584     created_models = set()
585     pending_references = {}
586
587     model_list = models.get_models(app)
588     for model in model_list:
589         # Create the model's database table, if it doesn't already exist.
590         if model._meta.db_table in table_list or model._meta.aka in table_list or len(set(model._meta.aka) & set(table_list))>0:
591             continue
592         sql, references = _get_sql_model_create(model, seen_models)
593         seen_models.add(model)
594         created_models.add(model)
595         table_list.append(model._meta.db_table)
596
597     # get the existing models, minus the models we've just created
598     app_models = models.get_models(app)
599     for model in created_models:
600         if model in app_models:
601             app_models.remove(model)
602
603     for klass in app_models:
604        
605         output, new_table_name = schema_evolution.get_sql_evolution_check_for_changed_model_name(klass)
606         final_output.extend(output)
607        
608         output = schema_evolution.get_sql_evolution_check_for_changed_field_flags(klass, new_table_name)
609         final_output.extend(output)
610    
611         output = schema_evolution.get_sql_evolution_check_for_changed_field_name(klass, new_table_name)
612         final_output.extend(output)
613        
614         output = schema_evolution.get_sql_evolution_check_for_new_fields(klass, new_table_name)
615         final_output.extend(output)
616        
617         output = schema_evolution.get_sql_evolution_check_for_dead_fields(klass, new_table_name)
618         final_output.extend(output)
619        
620     return schema_fingerprint, True, final_output
621    
622 get_sql_evolution.help_doc = "Returns SQL to update an existing schema to match the existing models."
623 get_sql_evolution.args = APP_ARGS
624
625 def get_sql_all(app):
626     "Returns a list of CREATE TABLE SQL, initial-data inserts, and CREATE INDEX SQL for the given module."
627     return get_sql_create(app) + get_custom_sql(app) + get_sql_indexes(app)
628 get_sql_all.help_doc = "Prints the CREATE TABLE, initial-data and CREATE INDEX SQL statements for the given model module name(s)."
629 get_sql_all.args = APP_ARGS
630
631 def _emit_post_sync_signal(created_models, verbosity, interactive):
632     from django.db import models
633     from django.dispatch import dispatcher
634     # Emit the post_sync signal for every application.
635     for app in models.get_apps():
636         app_name = app.__name__.split('.')[-2]
637         if verbosity >= 2:
638             print "Running post-sync handlers for application", app_name
639         dispatcher.send(signal=models.signals.post_syncdb, sender=app,
640             app=app, created_models=created_models,
641             verbosity=verbosity, interactive=interactive)
642
643 def syncdb(verbosity=1, interactive=True):
644     "Creates the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
645     from django.db import backend, connection, transaction, models
646     from django.conf import settings
647
648     disable_termcolors()
649
650     # First, try validating the models.
651     _check_for_validation_errors()
652
653     # Import the 'management' module within each installed app, to register
654     # dispatcher events.
655     for app_name in settings.INSTALLED_APPS:
656         try:
657             __import__(app_name + '.management', {}, {}, [''])
658         except ImportError:
659             pass
660
661     cursor = connection.cursor()
662
663     # Get a list of all existing database tables,
664     # so we know what needs to be added.
665     table_list = _get_table_list()
666     if backend.uses_case_insensitive_names:
667         table_name_converter = str.upper
668     else:
669         table_name_converter = lambda x: x
670
671     # Get a list of already installed *models* so that references work right.
672     seen_models = _get_installed_models(table_list)
673     created_models = set()
674     pending_references = {}
675
676     # Create the tables for each model
677     for app in models.get_apps():
678         app_name = app.__name__.split('.')[-2]
679         model_list = models.get_models(app)
680         for model in model_list:
681             # Create the model's database table, if it doesn't already exist.
682             if verbosity >= 2:
683                 print "Processing %s.%s model" % (app_name, model._meta.object_name)
684             if table_name_converter(model._meta.db_table) in table_list or table_name_converter(model._meta.aka) in table_list or len(set(model._meta.aka) & set(table_list))>0:
685                 continue
686             sql, references = _get_sql_model_create(model, seen_models)
687             seen_models.add(model)
688             created_models.add(model)
689             for refto, refs in references.items():
690                 pending_references.setdefault(refto, []).extend(refs)
691             sql.extend(_get_sql_for_pending_references(model, pending_references))
692             if verbosity >= 1:
693                 print "Creating table %s" % model._meta.db_table
694             for statement in sql:
695                 cursor.execute(statement)
696             table_list.append(table_name_converter(model._meta.db_table))
697
698     # Create the m2m tables. This must be done after all tables have been created
699     # to ensure that all referred tables will exist.
700     for app in models.get_apps():
701         app_name = app.__name__.split('.')[-2]
702         model_list = models.get_models(app)
703         for model in model_list:
704             if model in created_models:
705                 sql = _get_many_to_many_sql_for_model(model)
706                 if sql:
707                     if verbosity >= 2:
708                         print "Creating many-to-many tables for %s.%s model" % (app_name, model._meta.object_name)
709                     for statement in sql:
710                         cursor.execute(statement)
711
712         # keep evolving until there is nothing left to do
713         schema_fingerprint, introspected_upgrade, evolution = get_sql_evolution_detailed(app)
714         last_schema_fingerprint = None
715         while evolution and schema_fingerprint!=last_schema_fingerprint:
716             for sql in evolution:
717                 if introspected_upgrade:
718                     print sql
719                 else:
720                     cursor.execute(sql)
721             last_schema_fingerprint = schema_fingerprint
722             if not introspected_upgrade: # only do one round of introspection generated upgrades
723                 schema_fingerprint, introspected_upgrade, evolution = get_sql_evolution_detailed(app)
724
725     transaction.commit_unless_managed()
726
727     # Send the post_syncdb signal, so individual apps can do whatever they need
728     # to do at this point.
729     _emit_post_sync_signal(created_models, verbosity, interactive)
730
731     # Install custom SQL for the app (but only if this
732     # is a model we've just created)
733     for app in models.get_apps():
734         app_name = app.__name__.split('.')[-2]
735         for model in models.get_models(app):
736             if model in created_models:
737                 custom_sql = get_custom_sql_for_model(model)
738                 if custom_sql:
739                     if verbosity >= 1:
740                         print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
741                     try:
742                         for sql in custom_sql:
743                             cursor.execute(sql)
744                     except Exception, e:
745                         sys.stderr.write("Failed to install custom SQL for %s.%s model: %s" % \
746                                             (app_name, model._meta.object_name, e))
747                         transaction.rollback_unless_managed()
748                     else:
749                         transaction.commit_unless_managed()
750
751     # Install SQL indicies for all newly created models
752     for app in models.get_apps():
753         app_name = app.__name__.split('.')[-2]
754         for model in models.get_models(app):
755             if model in created_models:
756                 index_sql = get_sql_indexes_for_model(model)
757                 if index_sql:
758                     if verbosity >= 1:
759                         print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
760                     try:
761                         for sql in index_sql:
762                             cursor.execute(sql)
763                     except Exception, e:
764                         sys.stderr.write("Failed to install index for %s.%s model: %s" % \
765                                             (app_name, model._meta.object_name, e))
766                         transaction.rollback_unless_managed()
767                     else:
768                         transaction.commit_unless_managed()
769
770     # Install the 'initialdata' fixture, using format discovery
771     load_data(['initial_data'], verbosity=verbosity)
772 syncdb.help_doc = "Create the database tables for all apps in INSTALLED_APPS whose tables haven't already been created."
773 syncdb.args = '[--verbosity] [--noinput]'
774
775 def get_admin_index(app):
776     "Returns admin-index template snippet (in list form) for the given app."
777     from django.utils.text import capfirst
778     from django.db.models import get_models
779     output = []
780     app_models = get_models(app)
781     app_label = app_models[0]._meta.app_label
782     output.append('{%% if perms.%s %%}' % app_label)
783     output.append('<div class="module"><h2>%s</h2><table>' % app_label.title())
784     for model in app_models:
785         if model._meta.admin:
786             output.append(MODULE_TEMPLATE % {
787                 'app': app_label,
788                 'mod': model._meta.module_name,
789                 'name': capfirst(model._meta.verbose_name_plural),
790                 'addperm': model._meta.get_add_permission(),
791                 'changeperm': model._meta.get_change_permission(),
792             })
793     output.append('</table></div>')
794     output.append('{% endif %}')
795     return output
796 get_admin_index.help_doc = "Prints the admin-index template snippet for the given app name(s)."
797 get_admin_index.args = APP_ARGS
798
799 def _module_to_dict(module, omittable=lambda k: k.startswith('_')):
800     "Converts a module namespace to a Python dictionary. Used by get_settings_diff."
801     return dict([(k, repr(v)) for k, v in module.__dict__.items() if not omittable(k)])
802
803 def diffsettings():
804     """
805     Displays differences between the current settings.py and Django's
806     default settings. Settings that don't appear in the defaults are
807     followed by "###".
808     """
809     # Inspired by Postfix's "postconf -n".
810     from django.conf import settings, global_settings
811
812     user_settings = _module_to_dict(settings._target)
813     default_settings = _module_to_dict(global_settings)
814
815     output = []
816     keys = user_settings.keys()
817     keys.sort()
818     for key in keys:
819         if key not in default_settings:
820             output.append("%s = %s  ###" % (key, user_settings[key]))
821         elif user_settings[key] != default_settings[key]:
822             output.append("%s = %s" % (key, user_settings[key]))
823     print '\n'.join(output)
824 diffsettings.args = ""
825
826 def reset(app, interactive=True):
827     "Executes the equivalent of 'get_sql_reset' in the current database."
828     from django.db import connection, transaction
829     from django.conf import settings
830     app_name = app.__name__.split('.')[-2]
831
832     disable_termcolors()
833
834     # First, try validating the models.
835     _check_for_validation_errors(app)
836     sql_list = get_sql_reset(app)
837
838     if interactive:
839         confirm = raw_input("""
840 You have requested a database reset.
841 This will IRREVERSIBLY DESTROY any data for
842 the "%s" application in the database "%s".
843 Are you sure you want to do this?
844
845 Type 'yes' to continue, or 'no' to cancel: """ % (app_name, settings.DATABASE_NAME))
846     else:
847         confirm = 'yes'
848
849     if confirm == 'yes':
850         try:
851             cursor = connection.cursor()
852             for sql in sql_list:
853                 cursor.execute(sql)
854         except Exception, e:
855             sys.stderr.write(style.ERROR("""Error: %s couldn't be reset. Possible reasons:
856   * The database isn't running or isn't configured correctly.
857   * At least one of the database tables doesn't exist.
858   * The SQL was invalid.
859 Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this command wasn't able to run.
860 The full error: """ % (app_name, app_name)) + style.ERROR_OUTPUT(str(e)) + '\n')
861             transaction.rollback_unless_managed()
862             sys.exit(1)
863         transaction.commit_unless_managed()
864     else:
865         print "Reset cancelled."
866 reset.help_doc = "Executes ``sqlreset`` for the given app(s) in the current database."
867 reset.args = '[--noinput]' + APP_ARGS
868
869 def flush(verbosity=1, interactive=True):
870     "Returns all tables in the database to the same state they were in immediately after syncdb."
871     from django.conf import settings
872     from django.db import connection, transaction, models
873     from django.dispatch import dispatcher
874
875     disable_termcolors()
876
877     # First, try validating the models.
878     _check_for_validation_errors()
879
880     # Import the 'management' module within each installed app, to register
881     # dispatcher events.
882     for app_name in settings.INSTALLED_APPS:
883         try:
884             __import__(app_name + '.management', {}, {}, [''])
885         except ImportError:
886             pass
887
888     sql_list = get_sql_flush()
889
890     if interactive:
891         confirm = raw_input("""
892 You have requested a flush of the database.
893 This will IRREVERSIBLY DESTROY all data currently in the database,
894 and return each table to the state it was in after syncdb.
895 Are you sure you want to do this?
896
897 Type 'yes' to continue, or 'no' to cancel: """)
898     else:
899         confirm = 'yes'
900
901     if confirm == 'yes':
902         try:
903             cursor = connection.cursor()
904             for sql in sql_list:
905                 cursor.execute(sql)
906         except Exception, e:
907             sys.stderr.write(style.ERROR("""Error: Database %s couldn't be flushed. Possible reasons:
908   * The database isn't running or isn't configured correctly.
909   * At least one of the expected database tables doesn't exist.
910   * The SQL was invalid.
911 Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.
912 The full error: """ % settings.DATABASE_NAME + style.ERROR_OUTPUT(str(e)) + '\n'))
913             transaction.rollback_unless_managed()
914             sys.exit(1)
915         transaction.commit_unless_managed()
916
917         # Emit the post sync signal. This allows individual
918         # applications to respond as if the database had been
919         # sync'd from scratch.
920         _emit_post_sync_signal(models.get_models(), verbosity, interactive)
921
922         # Reinstall the initial_data fixture
923         load_data(['initial_data'], verbosity=verbosity)
924
925     else:
926         print "Flush cancelled."
927 flush.help_doc = "Executes ``sqlflush`` on the current database."
928 flush.args = '[--verbosity] [--noinput]'
929
930 def _start_helper(app_or_project, name, directory, other_name=''):
931     other = {'project': 'app', 'app': 'project'}[app_or_project]
932     if not _is_valid_dir_name(name):
933         sys.stderr.write(style.ERROR("Error: %r is not a valid %s name. Please use only numbers, letters and underscores.\n" % (name, app_or_project)))
934         sys.exit(1)
935     top_dir = os.path.join(directory, name)
936     try:
937         os.mkdir(top_dir)
938     except OSError, e:
939         sys.stderr.write(style.ERROR("Error: %s\n" % e))
940         sys.exit(1)
941     template_dir = PROJECT_TEMPLATE_DIR % app_or_project
942     for d, subdirs, files in os.walk(template_dir):
943         relative_dir = d[len(template_dir)+1:].replace('%s_name' % app_or_project, name)
944         if relative_dir:
945             os.mkdir(os.path.join(top_dir, relative_dir))
946         for i, subdir in enumerate(subdirs):
947             if subdir.startswith('.'):
948                 del subdirs[i]
949         for f in files:
950             if f.endswith('.pyc'):
951                 continue
952             path_old = os.path.join(d, f)
953             path_new = os.path.join(top_dir, relative_dir, f.replace('%s_name' % app_or_project, name))
954             fp_old = open(path_old, 'r')
955             fp_new = open(path_new, 'w')
956             fp_new.write(fp_old.read().replace('{{ %s_name }}' % app_or_project, name).replace('{{ %s_name }}' % other, other_name))
957             fp_old.close()
958             fp_new.close()
959             try:
960                 shutil.copymode(path_old, path_new)
961             except OSError:
962                 sys.stderr.write(style.NOTICE("Notice: Couldn't set permission bits on %s. You're probably using an uncommon filesystem setup. No problem.\n" % path_new))
963
964 def startproject(project_name, directory):
965     "Creates a Django project for the given project_name in the given directory."
966     from random import choice
967     if project_name in INVALID_PROJECT_NAMES:
968         sys.stderr.write(style.ERROR("Error: '%r' conflicts with the name of an existing Python module and cannot be used as a project name. Please try another name.\n" % project_name))
969         sys.exit(1)
970     _start_helper('project', project_name, directory)
971
972     # Create a random SECRET_KEY hash, and put it in the main settings.
973     main_settings_file = os.path.join(directory, project_name, 'settings.py')
974     settings_contents = open(main_settings_file, 'r').read()
975
976     # If settings.py was copied from a read-only source, make it writeable.
977     if not os.access(main_settings_file, os.W_OK):
978         os.chmod(main_settings_file, 0600)
979
980     fp = open(main_settings_file, 'w')
981     secret_key = ''.join([choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)])
982     settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
983     fp.write(settings_contents)
984     fp.close()
985 startproject.help_doc = "Creates a Django project directory structure for the given project name in the current directory."
986 startproject.args = "[projectname]"
987
988 def startapp(app_name, directory):
989     "Creates a Django app for the given app_name in the given directory."
990     # Determine the project_name a bit naively -- by looking at the name of
991     # the parent directory.
992     project_dir = os.path.normpath(os.path.join(directory, '..'))
993     parent_dir = os.path.basename(project_dir)
994     project_name = os.path.basename(directory)
995     if app_name == project_name:
996         sys.stderr.write(style.ERROR("Error: You cannot create an app with the same name (%r) as your project.\n" % app_name))
997         sys.exit(1)
998     _start_helper('app', app_name, directory, parent_dir)
999 startapp.help_doc = "Creates a Django app directory structure for the given app name in the current directory."
1000 startapp.args = "[appname]"
1001
1002 def inspectdb():
1003     "Generator that introspects the tables in the given database name and returns a Django model, one line at a time."
1004     from django.db import connection, get_introspection_module
1005     import keyword
1006
1007     introspection_module = get_introspection_module()
1008
1009     table2model = lambda table_name: table_name.title().replace('_', '')
1010
1011     cursor = connection.cursor()
1012     yield "# This is an auto-generated Django model module."
1013     yield "# You'll have to do the following manually to clean this up:"
1014     yield "#     * Rearrange models' order"
1015     yield "#     * Make sure each model has one field with primary_key=True"
1016     yield "# Feel free to rename the models, but don't rename db_table values or field names."
1017     yield "#"
1018     yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'"
1019     yield "# into your database."
1020     yield ''
1021     yield 'from django.db import models'
1022     yield ''
1023     for table_name in introspection_module.get_table_list(cursor):
1024         yield 'class %s(models.Model):' % table2model(table_name)
1025         try:
1026             relations = introspection_module.get_relations(cursor, table_name)
1027         except NotImplementedError:
1028             relations = {}
1029         try:
1030             indexes = introspection_module.get_indexes(cursor, table_name)
1031         except NotImplementedError:
1032             indexes = {}
1033         for i, row in enumerate(introspection_module.get_table_description(cursor, table_name)):
1034             att_name = row[0].lower()
1035             comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
1036             extra_params = {}  # Holds Field parameters such as 'db_column'.
1037
1038             if ' ' in att_name:
1039                 extra_params['db_column'] = att_name
1040                 att_name = att_name.replace(' ', '')
1041                 comment_notes.append('Field renamed to remove spaces.')
1042             if keyword.iskeyword(att_name):
1043                 extra_params['db_column'] = att_name
1044                 att_name += '_field'
1045                 comment_notes.append('Field renamed because it was a Python reserved word.')
1046
1047             if i in relations:
1048                 rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1])
1049                 field_type = 'ForeignKey(%s' % rel_to
1050                 if att_name.endswith('_id'):
1051                     att_name = att_name[:-3]
1052                 else:
1053                     extra_params['db_column'] = att_name
1054             else:
1055                 try:
1056                     field_type = introspection_module.DATA_TYPES_REVERSE[row[1]]
1057                 except KeyError:
1058                     field_type = 'TextField'
1059                     comment_notes.append('This field type is a guess.')
1060
1061                 # This is a hook for DATA_TYPES_REVERSE to return a tuple of
1062                 # (field_type, extra_params_dict).
1063                 if type(field_type) is tuple:
1064                     field_type, new_params = field_type
1065                     extra_params.update(new_params)
1066
1067                 # Add max_length for all CharFields.
1068                 if field_type == 'CharField' and row[3]:
1069                     extra_params['max_length'] = row[3]
1070
1071                 if field_type == 'DecimalField':
1072                     extra_params['max_digits'] = row[4]
1073                     extra_params['decimal_places'] = row[5]
1074
1075                 # Add primary_key and unique, if necessary.
1076                 column_name = extra_params.get('db_column', att_name)
1077                 if column_name in indexes:
1078                     if indexes[column_name]['primary_key']:
1079                         extra_params['primary_key'] = True
1080                     elif indexes[column_name]['unique']:
1081                         extra_params['unique'] = True
1082
1083                 field_type += '('
1084
1085             # Don't output 'id = meta.AutoField(primary_key=True)', because
1086             # that's assumed if it doesn't exist.
1087             if att_name == 'id' and field_type == 'AutoField(' and extra_params == {'primary_key': True}:
1088                 continue
1089
1090             # Add 'null' and 'blank', if the 'null_ok' flag was present in the
1091             # table description.
1092             if row[6]: # If it's NULL...
1093                 extra_params['blank'] = True
1094                 if not field_type in ('TextField(', 'CharField('):
1095                     extra_params['null'] = True
1096
1097             field_desc = '%s = models.%s' % (att_name, field_type)
1098             if extra_params:
1099                 if not field_desc.endswith('('):
1100                     field_desc += ', '
1101                 field_desc += ', '.join(['%s=%r' % (k, v) for k, v in extra_params.items()])
1102             field_desc += ')'
1103             if comment_notes:
1104                 field_desc += ' # ' + ' '.join(comment_notes)
1105             yield '    %s' % field_desc
1106         yield '    class Meta:'
1107         yield '        db_table = %r' % table_name
1108         yield ''
1109 inspectdb.help_doc = "Introspects the database tables in the given database and outputs a Django model module."
1110 inspectdb.args = ""
1111
1112 class ModelErrorCollection:
1113     def __init__(self, outfile=sys.stdout):
1114         self.errors = []
1115         self.outfile = outfile
1116
1117     def add(self, context, error):
1118         self.errors.append((context, error))
1119         self.outfile.write(style.ERROR("%s: %s\n" % (context, error)))
1120
1121 def get_validation_errors(outfile, app=None):
1122     """
1123     Validates all models that are part of the specified app. If no app name is provided,
1124     validates all models of all installed apps. Writes errors, if any, to outfile.
1125     Returns number of errors.
1126     """
1127     from django.conf import settings
1128     from django.db import models, connection
1129     from django.db.models.loading import get_app_errors
1130     from django.db.models.fields.related import RelatedObject
1131
1132     e = ModelErrorCollection(outfile)
1133
1134     for (app_name, error) in get_app_errors().items():
1135         e.add(app_name, error)
1136
1137     for cls in models.get_models(app):
1138         opts = cls._meta
1139
1140         # Do field-specific validation.
1141         for f in opts.fields:
1142             if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
1143                 e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
1144             if isinstance(f, models.CharField) and f.max_length in (None, 0):
1145                 e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name)
1146             if isinstance(f, models.DecimalField):
1147                 if f.decimal_places is None:
1148                     e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
1149                 if f.max_digits is None:
1150                     e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name)
1151             if isinstance(f, models.FileField) and not f.upload_to:
1152                 e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
1153             if isinstance(f, models.ImageField):
1154                 try:
1155                     from PIL import Image
1156                 except ImportError:
1157                     e.add(opts, '"%s": To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ .' % f.name)
1158             if f.prepopulate_from is not None and type(f.prepopulate_from) not in (list, tuple):
1159                 e.add(opts, '"%s": prepopulate_from should be a list or tuple.' % f.name)
1160             if f.choices:
1161                 if not hasattr(f.choices, '__iter__'):
1162                     e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
1163                 else:
1164                     for c in f.choices:
1165                         if not type(c) in (tuple, list) or len(c) != 2:
1166                             e.add(opts, '"%s": "choices" should be a sequence of two-tuples.' % f.name)
1167             if f.db_index not in (None, True, False):
1168                 e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name)
1169
1170             # Check that max_length <= 255 if using older MySQL versions.
1171             if settings.DATABASE_ENGINE == 'mysql':
1172                 db_version = connection.get_server_version()
1173                 if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255:
1174                     e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]])))
1175
1176             # Check to see if the related field will clash with any
1177             # existing fields, m2m fields, m2m related objects or related objects
1178             if f.rel:
1179                 rel_opts = f.rel.to._meta
1180                 if f.rel.to not in models.get_models():
1181                     e.add(opts, "'%s' has relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
1182
1183                 rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
1184                 rel_query_name = f.related_query_name()
1185                 for r in rel_opts.fields:
1186                     if r.name == rel_name:
1187                         e.add(opts, "Accessor for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1188                     if r.name == rel_query_name:
1189                         e.add(opts, "Reverse query name for field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1190                 for r in rel_opts.many_to_many:
1191                     if r.name == rel_name:
1192                         e.add(opts, "Accessor for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1193                     if r.name == rel_query_name:
1194                         e.add(opts, "Reverse query name for field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1195                 for r in rel_opts.get_all_related_many_to_many_objects():
1196                     if r.get_accessor_name() == rel_name:
1197                         e.add(opts, "Accessor for field '%s' clashes with related m2m 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))
1198                     if r.get_accessor_name() == rel_query_name:
1199                         e.add(opts, "Reverse query name for field '%s' clashes with related m2m 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))
1200                 for r in rel_opts.get_all_related_objects():
1201                     if r.field is not f:
1202                         if r.get_accessor_name() == rel_name:
1203                             e.add(opts, "Accessor for 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))
1204                         if r.get_accessor_name() == rel_query_name:
1205                             e.add(opts, "Reverse query name for 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))
1206
1207
1208         for i, f in enumerate(opts.many_to_many):
1209             # Check to see if the related m2m field will clash with any
1210             # existing fields, m2m fields, m2m related objects or related objects
1211             rel_opts = f.rel.to._meta
1212             if f.rel.to not in models.get_models():
1213                 e.add(opts, "'%s' has m2m relation with model %s, which has not been installed" % (f.name, rel_opts.object_name))
1214
1215             rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name()
1216             rel_query_name = f.related_query_name()
1217             # If rel_name is none, there is no reverse accessor.
1218             # (This only occurs for symmetrical m2m relations to self).
1219             # If this is the case, there are no clashes to check for this field, as
1220             # there are no reverse descriptors for this field.
1221             if rel_name is not None:
1222                 for r in rel_opts.fields:
1223                     if r.name == rel_name:
1224                         e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1225                     if r.name == rel_query_name:
1226                         e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1227                 for r in rel_opts.many_to_many:
1228                     if r.name == rel_name:
1229                         e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1230                     if r.name == rel_query_name:
1231                         e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name))
1232                 for r in rel_opts.get_all_related_many_to_many_objects():
1233                     if r.field is not f:
1234                         if r.get_accessor_name() == rel_name:
1235                             e.add(opts, "Accessor for m2m field '%s' clashes with related m2m 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))
1236                         if r.get_accessor_name() == rel_query_name:
1237                             e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m 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))
1238                 for r in rel_opts.get_all_related_objects():
1239                     if r.get_accessor_name() == rel_name:
1240                         e.add(opts, "Accessor 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))
1241                     if r.get_accessor_name() == rel_query_name:
1242                         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))
1243
1244         # Check admin attribute.
1245         if opts.admin is not None:
1246             if not isinstance(opts.admin, models.AdminOptions):
1247                 e.add(opts, '"admin" attribute, if given, must be set to a models.AdminOptions() instance.')
1248             else:
1249                 # list_display
1250                 if not isinstance(opts.admin.list_display, (list, tuple)):
1251                     e.add(opts, '"admin.list_display", if given, must be set to a list or tuple.')
1252                 else:
1253                     for fn in opts.admin.list_display:
1254                         try:
1255                             f = opts.get_field(fn)
1256                         except models.FieldDoesNotExist:
1257                             if not hasattr(cls, fn):
1258                                 e.add(opts, '"admin.list_display" refers to %r, which isn\'t an attribute, method or property.' % fn)
1259                         else:
1260                             if isinstance(f, models.ManyToManyField):
1261                                 e.add(opts, '"admin.list_display" doesn\'t support ManyToManyFields (%r).' % fn)
1262                 # list_display_links
1263                 if opts.admin.list_display_links and not opts.admin.list_display:
1264                     e.add(opts, '"admin.list_display" must be defined for "admin.list_display_links" to be used.')
1265                 if not isinstance(opts.admin.list_display_links, (list, tuple)):
1266                     e.add(opts, '"admin.list_display_links", if given, must be set to a list or tuple.')
1267                 else:
1268                     for fn in opts.admin.list_display_links:
1269                         try:
1270                             f = opts.get_field(fn)
1271                         except models.FieldDoesNotExist:
1272                             if not hasattr(cls, fn):
1273                                 e.add(opts, '"admin.list_display_links" refers to %r, which isn\'t an attribute, method or property.' % fn)
1274                         if fn not in opts.admin.list_display:
1275                             e.add(opts, '"admin.list_display_links" refers to %r, which is not defined in "admin.list_display".' % fn)
1276                 # list_filter
1277                 if not isinstance(opts.admin.list_filter, (list, tuple)):
1278                     e.add(opts, '"admin.list_filter", if given, must be set to a list or tuple.')
1279                 else:
1280                     for fn in opts.admin.list_filter:
1281                         try:
1282                             f = opts.get_field(fn)
1283                         except models.FieldDoesNotExist:
1284                             e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn)
1285                 # date_hierarchy
1286                 if opts.admin.date_hierarchy:
1287                     try:
1288                         f = opts.get_field(opts.admin.date_hierarchy)
1289                     except models.FieldDoesNotExist:
1290                         e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy)
1291
1292         # Check ordering attribute.
1293         if opts.ordering:
1294             for field_name in opts.ordering:
1295                 if field_name == '?': continue
1296                 if field_name.startswith('-'):
1297                     field_name = field_name[1:]
1298                 if opts.order_with_respect_to and field_name == '_order':
1299                     continue
1300                 if '.' in field_name: continue # Skip ordering in the format 'table.field'.
1301                 try:
1302                     opts.get_field(field_name, many_to_many=False)
1303                 except models.FieldDoesNotExist:
1304                     e.add(opts, '"ordering" refers to "%s", a field that doesn\'t exist.' % field_name)
1305
1306         # Check core=True, if needed.
1307         for related in opts.get_followed_related_objects():
1308             if not related.edit_inline:
1309                 continue
1310             try:
1311                 for f in related.opts.fields:
1312                     if f.core:
1313                         raise StopIteration
1314                 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))
1315             except StopIteration:
1316                 pass
1317
1318         # Check unique_together.
1319         for ut in opts.unique_together:
1320             for field_name in ut:
1321                 try:
1322                     f = opts.get_field(field_name, many_to_many=True)
1323                 except models.FieldDoesNotExist:
1324                     e.add(opts, '"unique_together" refers to %s, a field that doesn\'t exist. Check your syntax.' % field_name)
1325                 else:
1326                     if isinstance(f.rel, models.ManyToManyRel):
1327                         e.add(opts, '"unique_together" refers to %s. ManyToManyFields are not supported in unique_together.' % f.name)
1328
1329     return len(e.errors)
1330
1331 def validate(outfile=sys.stdout, silent_success=False):
1332     "Validates all installed models."
1333     try:
1334         num_errors = get_validation_errors(outfile)
1335         if silent_success and num_errors == 0:
1336             return
1337         outfile.write('%s error%s found.\n' % (num_errors, num_errors != 1 and 's' or ''))
1338     except ImproperlyConfigured:
1339         outfile.write("Skipping validation because things aren't configured properly.\n")
1340 validate.args = ''
1341
1342 def _check_for_validation_errors(app=None):
1343     """Check that an app has no validation errors, and exit with errors if it does."""
1344     try:
1345         from cStringIO import StringIO
1346     except ImportError:
1347         from StringIO import StringIO
1348     s = StringIO()
1349     num_errors = get_validation_errors(s, app)
1350     if num_errors:
1351         if app:
1352             sys.stderr.write(style.ERROR("Error: %s couldn't be installed, because there were errors in your model:\n" % app))
1353         else:
1354             sys.stderr.write(style.ERROR("Error: Couldn't install apps, because there were errors in one or more models:\n"))
1355         s.seek(0)
1356         sys.stderr.write(s.read())
1357         sys.exit(1)
1358
1359 def runserver(addr, port, use_reloader=True, admin_media_dir=''):
1360     "Starts a lightweight Web server for development."
1361     from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException
1362     from django.core.handlers.wsgi import WSGIHandler
1363     if not addr:
1364         addr = '127.0.0.1'
1365     if not port.isdigit():
1366         sys.stderr.write(style.ERROR("Error: %r is not a valid port number.\n" % port))
1367         sys.exit(1)
1368     quit_command = sys.platform == 'win32' and 'CTRL-BREAK' or 'CONTROL-C'
1369     def inner_run():
1370         from django.conf import settings
1371         print "Validating models..."
1372         validate()
1373         print "\nDjango version %s, using settings %r" % (get_version(), settings.SETTINGS_MODULE)
1374         print "Development server is running at http://%s:%s/" % (addr, port)
1375         print "Quit the server with %s." % quit_command
1376         try:
1377             import django
1378             path = admin_media_dir or django.__path__[0] + '/contrib/admin/media'
1379             handler = AdminMediaHandler(WSGIHandler(), path)
1380             run(addr, int(port), handler)
1381         except WSGIServerException, e:
1382             # Use helpful error messages instead of ugly tracebacks.
1383             ERRORS = {
1384                 13: "You don't have permission to access that port.",
1385                 98: "That port is already in use.",
1386                 99: "That IP address can't be assigned-to.",
1387             }
1388             try:
1389                 error_text = ERRORS[e.args[0].args[0]]
1390             except (AttributeError, KeyError):
1391                 error_text = str(e)
1392             sys.stderr.write(style.ERROR("Error: %s" % error_text) + '\n')
1393             # Need to use an OS exit because sys.exit doesn't work in a thread
1394             os._exit(1)
1395         except KeyboardInterrupt:
1396             sys.exit(0)
1397     if use_reloader:
1398         from django.utils import autoreload
1399         autoreload.main(inner_run)
1400     else:
1401         inner_run()
1402 runserver.args = '[--noreload] [--adminmedia=ADMIN_MEDIA_PATH] [optional port number, or ipaddr:port]'
1403
1404 def createcachetable(tablename):
1405     "Creates the table needed to use the SQL cache backend"
1406     from django.db import backend, connection, transaction, models
1407     fields = (
1408         # "key" is a reserved word in MySQL, so use "cache_key" instead.
1409         models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
1410         models.TextField(name='value'),
1411         models.DateTimeField(name='expires', db_index=True),
1412     )
1413     table_output = []
1414     index_output = []
1415     for f in fields:
1416         field_output = [backend.quote_name(f.name), f.db_type()]
1417         field_output.append("%sNULL" % (not f.null and "NOT " or ""))
1418         if f.unique:
1419             field_output.append("UNIQUE")
1420         if f.primary_key:
1421             field_output.append("PRIMARY KEY")
1422         if f.db_index:
1423             unique = f.unique and "UNIQUE " or ""
1424             index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
1425                 (unique, tablename, f.name, backend.quote_name(tablename),
1426                 backend.quote_name(f.name)))
1427         table_output.append(" ".join(field_output))
1428     full_statement = ["CREATE TABLE %s (" % backend.quote_name(tablename)]
1429     for i, line in enumerate(table_output):
1430         full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
1431     full_statement.append(');')
1432     curs = connection.cursor()
1433     curs.execute("\n".join(full_statement))
1434     for statement in index_output:
1435         curs.execute(statement)
1436     transaction.commit_unless_managed()
1437 createcachetable.args = "[tablename]"
1438
1439 def run_shell(use_plain=False):
1440     "Runs a Python interactive interpreter. Tries to use IPython, if it's available."
1441     # XXX: (Temporary) workaround for ticket #1796: force early loading of all
1442     # models from installed apps.
1443     from django.db.models.loading import get_models
1444     loaded_models = get_models()
1445
1446     try:
1447         if use_plain:
1448             # Don't bother loading IPython, because the user wants plain Python.
1449             raise ImportError
1450         import IPython
1451         # Explicitly pass an empty list as arguments, because otherwise IPython
1452         # would use sys.argv from this script.
1453         shell = IPython.Shell.IPShell(argv=[])
1454         shell.mainloop()
1455     except ImportError:
1456         import code
1457         # Set up a dictionary to serve as the environment for the shell, so
1458         # that tab completion works on objects that are imported at runtime.
1459         # See ticket 5082.
1460         imported_objects = {}
1461         try: # Try activating rlcompleter, because it's handy.
1462             import readline
1463         except ImportError:
1464             pass
1465         else:
1466             # We don't have to wrap the following import in a 'try', because
1467             # we already know 'readline' was imported successfully.
1468             import rlcompleter
1469             readline.set_completer(rlcompleter.Completer(imported_objects).complete)
1470             readline.parse_and_bind("tab:complete")
1471         code.interact(local=imported_objects)
1472 run_shell.args = '[--plain]'
1473
1474 def dbshell():
1475     "Runs the command-line client for the current DATABASE_ENGINE."
1476     from django.db import runshell
1477     runshell()
1478 dbshell.args = ""
1479
1480 def runfcgi(args):
1481     "Runs this project as a FastCGI application. Requires flup."
1482     from django.conf import settings
1483     from django.utils import translation
1484     # Activate the current language, because it won't get activated later.
1485     try:
1486         translation.activate(settings.LANGUAGE_CODE)
1487     except AttributeError:
1488         pass
1489     from django.core.servers.fastcgi import runfastcgi
1490     runfastcgi(args)
1491 runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
1492
1493 def test(test_labels, verbosity=1, interactive=True):
1494     "Runs the test suite for the specified applications"
1495     from django.conf import settings
1496     from django.db.models import get_app, get_apps
1497    
1498     test_path = settings.TEST_RUNNER.split('.')
1499     # Allow for Python 2.5 relative paths
1500     if len(test_path) > 1:
1501         test_module_name = '.'.join(test_path[:-1])
1502     else:
1503         test_module_name = '.'
1504     test_module = __import__(test_module_name, {}, {}, test_path[-1])
1505     test_runner = getattr(test_module, test_path[-1])
1506
1507     failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive)
1508     if failures:
1509         sys.exit(failures)
1510
1511 test.help_doc = 'Runs the test suite for the specified applications, or the entire site if no apps are specified'
1512 test.args = '[--verbosity] [--noinput]' + APP_ARGS
1513
1514 def load_data(fixture_labels, verbosity=1):
1515     "Installs the provided fixture file(s) as data in the database."
1516     from django.db.models import get_apps
1517     from django.core import serializers
1518     from django.db import connection, transaction, backend
1519     from django.conf import settings
1520     import sys
1521
1522     disable_termcolors()
1523
1524     # Keep a count of the installed objects and fixtures
1525     count = [0,0]
1526     models = set()
1527
1528     humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
1529
1530     # Get a cursor (even though we don't need one yet). This has
1531     # the side effect of initializing the test database (if
1532     # it isn't already initialized).
1533     cursor = connection.cursor()
1534
1535     # Start transaction management. All fixtures are installed in a
1536     # single transaction to ensure that all references are resolved.
1537     transaction.commit_unless_managed()
1538     transaction.enter_transaction_management()
1539     transaction.managed(True)
1540
1541     app_fixtures = [os.path.join(os.path.dirname(app.__file__),'fixtures') for app in get_apps()]
1542     for fixture_label in fixture_labels:
1543         parts = fixture_label.split('.')
1544         if len(parts) == 1:
1545             fixture_name = fixture_label
1546             formats = serializers.get_serializer_formats()
1547         else:
1548             fixture_name, format = '.'.join(parts[:-1]), parts[-1]
1549             if format in serializers.get_serializer_formats():
1550                 formats = [format]
1551             else:
1552                 formats = []
1553
1554         if verbosity > 0:
1555             if formats:
1556                 print "Loading '%s' fixtures..." % fixture_name
1557             else:
1558                 print "Skipping fixture '%s': %s is not a known serialization format" % (fixture_name, format)
1559
1560         for fixture_dir in app_fixtures + list(settings.FIXTURE_DIRS) + ['']:
1561             if verbosity > 1:
1562                 print "Checking %s for fixtures..." % humanize(fixture_dir)
1563
1564             label_found = False
1565             for format in formats:
1566                 serializer = serializers.get_serializer(format)
1567                 if verbosity > 1:
1568                     print "Trying %s for %s fixture '%s'..." % \
1569                         (humanize(fixture_dir), format, fixture_name)
1570                 try:
1571                     full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format]))
1572                     fixture = open(full_path, 'r')
1573                     if label_found:
1574                         fixture.close()
1575                         print style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
1576                             (fixture_name, humanize(fixture_dir)))
1577                         transaction.rollback()
1578                         transaction.leave_transaction_management()
1579                         return
1580                     else:
1581                         count[1] += 1
1582                         if verbosity > 0:
1583                             print "Installing %s fixture '%s' from %s." % \
1584                                 (format, fixture_name, humanize(fixture_dir))
1585                         try:
1586                             objects = serializers.deserialize(format, fixture)
1587                             for obj in objects:
1588                                 count[0] += 1
1589                                 models.add(obj.object.__class__)
1590                                 obj.save()
1591                             label_found = True
1592                         except Exception, e:
1593                             fixture.close()
1594                             sys.stderr.write(
1595                                 style.ERROR("Problem installing fixture '%s': %s\n" %
1596                                      (full_path, str(e))))
1597                             transaction.rollback()
1598                             transaction.leave_transaction_management()
1599                             return
1600                         fixture.close()
1601                 except:
1602                     if verbosity > 1:
1603                         print "No %s fixture '%s' in %s." % \
1604                             (format, fixture_name, humanize(fixture_dir))
1605
1606     if count[0] > 0:
1607         sequence_sql = backend.get_sql_sequence_reset(style, models)
1608         if sequence_sql:
1609             if verbosity > 1:
1610                 print "Resetting sequences"
1611             for line in sequence_sql:
1612                 cursor.execute(line)
1613
1614     transaction.commit()
1615     transaction.leave_transaction_management()
1616
1617     if count[0] == 0:
1618         if verbosity > 0:
1619             print "No fixtures found."
1620     else:
1621         if verbosity > 0:
1622             print "Installed %d object(s) from %d fixture(s)" % tuple(count)
1623
1624 load_data.help_doc = 'Installs the named fixture(s) in the database'
1625 load_data.args = "[--verbosity] fixture, fixture, ..."
1626
1627 def dump_data(app_labels, format='json', indent=None):
1628     "Output the current contents of the database as a fixture of the given format"
1629     from django.db.models import get_app, get_apps, get_models
1630     from django.core import serializers
1631
1632     if len(app_labels) == 0:
1633         app_list = get_apps()
1634     else:
1635         app_list = [get_app(app_label) for app_label in app_labels]
1636
1637     # Check that the serialization format exists; this is a shortcut to
1638     # avoid collating all the objects and _then_ failing.
1639     try:
1640         serializers.get_serializer(format)
1641     except KeyError:
1642         sys.stderr.write(style.ERROR("Unknown serialization format: %s\n" % format))
1643
1644     objects = []
1645     for app in app_list:
1646         for model in get_models(app):
1647             objects.extend(model.objects.all())
1648     try:
1649         return serializers.serialize(format, objects, indent=indent)
1650     except Exception, e:
1651         sys.stderr.write(style.ERROR("Unable to serialize database: %s\n" % e))
1652 dump_data.help_doc = 'Output the contents of the database as a fixture of the given format'
1653 dump_data.args = '[--format] [--indent]' + APP_ARGS
1654
1655 # Utilities for command-line script
1656
1657 DEFAULT_ACTION_MAPPING = {
1658     'adminindex': get_admin_index,
1659     'createcachetable' : createcachetable,
1660     'dbshell': dbshell,
1661     'diffsettings': diffsettings,
1662     'dumpdata': dump_data,
1663     'flush': flush,
1664     'inspectdb': inspectdb,
1665     'loaddata': load_data,
1666     'reset': reset,
1667     'runfcgi': runfcgi,
1668     'runserver': runserver,
1669     'shell': run_shell,
1670     'sql': get_sql_create,
1671     'sqlall': get_sql_all,
1672     'sqlclear': get_sql_delete,
1673     'sqlcustom': get_custom_sql,
1674     'sqlflush': get_sql_flush,
1675     'sqlindexes': get_sql_indexes,
1676     'sqlinitialdata': get_sql_initial_data,
1677     'sqlreset': get_sql_reset,
1678     'sqlsequencereset': get_sql_sequence_reset,
1679     'sqlevolve': get_sql_evolution,
1680     'sqlfingerprint': get_sql_fingerprint,
1681     'startapp': startapp,
1682     'startproject': startproject,
1683     'syncdb': syncdb,
1684     'validate': validate,
1685     'test':test,
1686 }
1687
1688 NO_SQL_TRANSACTION = (
1689     'adminindex',
1690     'createcachetable',
1691     'dbshell',
1692     'diffsettings',
1693     'reset',
1694     'sqlindexes',
1695     'syncdb',
1696 )
1697
1698 class DjangoOptionParser(OptionParser):
1699     def print_usage_and_exit(self):
1700         self.print_help(sys.stderr)
1701         sys.exit(1)
1702
1703 def get_usage(action_mapping):
1704     """
1705     Returns a usage string. Doesn't do the options stuff, because optparse
1706     takes care of that.
1707     """
1708     usage = ["%prog action [options]\nactions:"]
1709     available_actions = action_mapping.keys()
1710     available_actions.sort()
1711     for a in available_actions:
1712         func = action_mapping[a]
1713         usage.append(%s %s" % (a, func.args))
1714         usage.extend(textwrap.wrap(getattr(func, 'help_doc', textwrap.dedent(func.__doc__.strip())), initial_indent='    ', subsequent_indent='    '))
1715         usage.append("")
1716     return '\n'.join(usage[:-1]) # Cut off last list element, an empty space.
1717
1718 def print_error(msg, cmd):
1719     sys.stderr.write(style.ERROR('Error: %s' % msg) + '\nRun "%s --help" for help.\n' % cmd)
1720     sys.exit(1)
1721
1722 def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
1723     # Use sys.argv if we've not passed in a custom argv
1724     if argv is None:
1725         argv = sys.argv
1726
1727     # Parse the command-line arguments. optparse handles the dirty work.
1728     parser = DjangoOptionParser(usage=get_usage(action_mapping), version=get_version())
1729     parser.add_option('--settings',
1730         help='Python path to settings module, e.g. "myproject.settings.main". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.')
1731     parser.add_option('--pythonpath',
1732         help='Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".')
1733     parser.add_option('--plain', action='store_true', dest='plain',
1734         help='Tells Django to use plain Python, not IPython, for "shell" command.')
1735     parser.add_option('--noinput', action='store_false', dest='interactive', default=True,
1736         help='Tells Django to NOT prompt the user for input of any kind.')
1737     parser.add_option('--noreload', action='store_false', dest='use_reloader', default=True,
1738         help='Tells Django to NOT use the auto-reloader when running the development server.')
1739     parser.add_option('--format', default='json', dest='format',
1740         help='Specifies the output serialization format for fixtures')
1741     parser.add_option('--indent', default=None, dest='indent',
1742         type='int', help='Specifies the indent level to use when pretty-printing output')
1743     parser.add_option('--verbosity', action='store', dest='verbosity', default='1',
1744         type='choice', choices=['0', '1', '2'],
1745         help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
1746     parser.add_option('--adminmedia', dest='admin_media_path', default='', help='Specifies the directory from which to serve admin media for runserver.'),
1747
1748     options, args = parser.parse_args(argv[1:])
1749
1750     # Take care of options.
1751     if options.settings:
1752         os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
1753     if options.pythonpath:
1754         sys.path.insert(0, options.pythonpath)
1755
1756     # Run the appropriate action. Unfortunately, optparse can't handle
1757     # positional arguments, so this has to parse/validate them.
1758     try:
1759         action = args[0]
1760     except IndexError:
1761         parser.print_usage_and_exit()
1762     if action not in action_mapping:
1763         print_error("Your action, %r, was invalid." % action, argv[0])
1764
1765     # Switch to English, because django-admin.py creates database content
1766     # like permissions, and those shouldn't contain any translations.
1767     # But only do this if we should have a working settings file.
1768     if action not in ('startproject', 'startapp'):
1769         from django.utils import translation
1770         translation.activate('en-us')
1771
1772     if action == 'shell':
1773         action_mapping[action](options.plain is True)
1774     elif action in ('validate', 'diffsettings', 'dbshell'):
1775         action_mapping[action]()
1776     elif action in ('flush', 'syncdb'):
1777         action_mapping[action](int(options.verbosity), options.interactive)
1778     elif action == 'inspectdb':
1779         try:
1780             for line in action_mapping[action]():
1781                 print line
1782         except NotImplementedError:
1783             sys.stderr.write(style.ERROR("Error: %r isn't supported for the currently selected database backend.\n" % action))
1784             sys.exit(1)
1785     elif action == 'createcachetable':
1786         try:
1787             action_mapping[action](args[1])
1788         except IndexError:
1789             parser.print_usage_and_exit()
1790     elif action == 'test':
1791         try:
1792             action_mapping[action](args[1:], int(options.verbosity), options.interactive)
1793         except IndexError:
1794             parser.print_usage_and_exit()
1795     elif action == 'loaddata':
1796         try:
1797             action_mapping[action](args[1:], int(options.verbosity))
1798         except IndexError:
1799             parser.print_usage_and_exit()
1800     elif action == 'dumpdata':
1801         try:
1802             print action_mapping[action](args[1:], options.format, options.indent)
1803         except IndexError:
1804             parser.print_usage_and_exit()
1805     elif action in ('startapp', 'startproject'):
1806         try:
1807             name = args[1]
1808         except IndexError:
1809             parser.print_usage_and_exit()
1810         action_mapping[action](name, os.getcwd())
1811     elif action == 'runserver':
1812         if len(args) < 2:
1813             addr = ''
1814             port = '8000'
1815         else:
1816             try:
1817                 addr, port = args[1].split(':')
1818             except ValueError:
1819                 addr, port = '', args[1]
1820         action_mapping[action](addr, port, options.use_reloader, options.admin_media_path)
1821     elif action == 'runfcgi':
1822         action_mapping[action](args[1:])
1823     elif action == 'sqlinitialdata':
1824         print action_mapping[action](args[1:])
1825     elif action == 'sqlflush':
1826         print '\n'.join(action_mapping[action]())
1827     else:
1828         from django.db import models
1829         validate(silent_success=True)
1830         try:
1831             mod_list = [models.get_app(app_label) for app_label in args[1:]]
1832         except ImportError, e:
1833             sys.stderr.write(style.ERROR("Error: %s. Are you sure your INSTALLED_APPS setting is correct?\n" % e))
1834             sys.exit(1)
1835         if not mod_list:
1836             parser.print_usage_and_exit()
1837         if action not in NO_SQL_TRANSACTION:
1838             from django.db import backend
1839             if backend.get_start_transaction_sql():
1840                 print style.SQL_KEYWORD(backend.get_start_transaction_sql())
1841         for mod in mod_list:
1842             if action == 'reset':
1843                 output = action_mapping[action](mod, options.interactive)
1844             else:
1845                 output = action_mapping[action](mod)
1846             if output:
1847                 print '\n'.join(output)
1848         if action not in NO_SQL_TRANSACTION:
1849             print style.SQL_KEYWORD("COMMIT;")
1850
1851 def setup_environ(settings_mod):
1852     """
1853     Configure the runtime environment. This can also be used by external
1854     scripts wanting to set up a similar environment to manage.py.
1855     """
1856     # Add this project to sys.path so that it's importable in the conventional
1857     # way. For example, if this file (manage.py) lives in a directory
1858     # "myproject", this code would add "/path/to/myproject" to sys.path.
1859     project_directory, settings_filename = os.path.split(settings_mod.__file__)
1860     project_name = os.path.basename(project_directory)
1861     settings_name = os.path.splitext(settings_filename)[0]
1862     sys.path.append(os.path.join(project_directory, '..'))
1863     project_module = __import__(project_name, {}, {}, [''])
1864     sys.path.pop()
1865
1866     # Set DJANGO_SETTINGS_MODULE appropriately.
1867     os.environ['DJANGO_SETTINGS_MODULE'] = '%s.%s' % (project_name, settings_name)
1868     return project_directory
1869
1870 def execute_manager(settings_mod, argv=<