2013-06-19 22:36:22 +08:00
|
|
|
import sys
|
2013-06-19 23:23:52 +08:00
|
|
|
import os
|
2013-06-19 22:36:22 +08:00
|
|
|
from optparse import make_option
|
|
|
|
|
|
|
|
from django.core.management.base import BaseCommand
|
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
2013-08-12 23:40:41 +08:00
|
|
|
from django.db import connections, DEFAULT_DB_ALIAS
|
2013-06-19 22:36:22 +08:00
|
|
|
from django.db.migrations.loader import MigrationLoader
|
|
|
|
from django.db.migrations.autodetector import MigrationAutodetector, InteractiveMigrationQuestioner
|
|
|
|
from django.db.migrations.state import ProjectState
|
2013-06-19 23:23:52 +08:00
|
|
|
from django.db.migrations.writer import MigrationWriter
|
2013-06-19 22:36:22 +08:00
|
|
|
from django.db.models.loading import cache
|
|
|
|
|
|
|
|
|
|
|
|
class Command(BaseCommand):
|
|
|
|
option_list = BaseCommand.option_list + (
|
|
|
|
make_option('--empty', action='store_true', dest='empty', default=False,
|
|
|
|
help='Make a blank migration.'),
|
|
|
|
)
|
|
|
|
|
|
|
|
help = "Creates new migration(s) for apps."
|
2013-06-20 22:27:33 +08:00
|
|
|
usage_str = "Usage: ./manage.py makemigrations [--empty] [app [app ...]]"
|
2013-06-19 22:36:22 +08:00
|
|
|
|
|
|
|
def handle(self, *app_labels, **options):
|
|
|
|
|
|
|
|
self.verbosity = int(options.get('verbosity'))
|
|
|
|
self.interactive = options.get('interactive')
|
|
|
|
|
|
|
|
# Make sure the app they asked for exists
|
|
|
|
app_labels = set(app_labels)
|
2013-08-11 03:02:55 +08:00
|
|
|
bad_app_labels = set()
|
2013-06-19 22:36:22 +08:00
|
|
|
for app_label in app_labels:
|
|
|
|
try:
|
|
|
|
cache.get_app(app_label)
|
|
|
|
except ImproperlyConfigured:
|
2013-08-11 03:02:55 +08:00
|
|
|
bad_app_labels.add(app_label)
|
|
|
|
if bad_app_labels:
|
|
|
|
for app_label in bad_app_labels:
|
|
|
|
self.stderr.write("App '%s' could not be found. Is it in INSTALLED_APPS?" % app_label)
|
|
|
|
sys.exit(2)
|
2013-06-19 22:36:22 +08:00
|
|
|
|
2013-08-11 04:04:59 +08:00
|
|
|
# Load the current graph state. Takes a connection, but it's not used
|
|
|
|
# (makemigrations doesn't look at the database state).
|
2013-08-12 23:40:41 +08:00
|
|
|
loader = MigrationLoader(connections[DEFAULT_DB_ALIAS])
|
2013-06-19 22:36:22 +08:00
|
|
|
|
|
|
|
# Detect changes
|
|
|
|
autodetector = MigrationAutodetector(
|
|
|
|
loader.graph.project_state(),
|
|
|
|
ProjectState.from_app_cache(cache),
|
|
|
|
InteractiveMigrationQuestioner(specified_apps=app_labels),
|
|
|
|
)
|
2013-08-22 05:25:15 +08:00
|
|
|
changes = autodetector.changes(graph=loader.graph, trim_to_apps=app_labels or None)
|
2013-06-19 22:36:22 +08:00
|
|
|
|
2013-06-19 23:23:52 +08:00
|
|
|
# No changes? Tell them.
|
|
|
|
if not changes:
|
|
|
|
if len(app_labels) == 1:
|
|
|
|
self.stdout.write("No changes detected in app '%s'" % app_labels.pop())
|
|
|
|
elif len(app_labels) > 1:
|
|
|
|
self.stdout.write("No changes detected in apps '%s'" % ("', '".join(app_labels)))
|
|
|
|
else:
|
|
|
|
self.stdout.write("No changes detected")
|
|
|
|
return
|
|
|
|
|
|
|
|
for app_label, migrations in changes.items():
|
|
|
|
self.stdout.write(self.style.MIGRATE_HEADING("Migrations for '%s':" % app_label) + "\n")
|
|
|
|
for migration in migrations:
|
|
|
|
# Describe the migration
|
|
|
|
writer = MigrationWriter(migration)
|
|
|
|
self.stdout.write(" %s:\n" % (self.style.MIGRATE_LABEL(writer.filename),))
|
|
|
|
for operation in migration.operations:
|
|
|
|
self.stdout.write(" - %s\n" % operation.describe())
|
|
|
|
# Write it
|
|
|
|
migrations_directory = os.path.dirname(writer.path)
|
|
|
|
if not os.path.isdir(migrations_directory):
|
|
|
|
os.mkdir(migrations_directory)
|
|
|
|
init_path = os.path.join(migrations_directory, "__init__.py")
|
|
|
|
if not os.path.isfile(init_path):
|
|
|
|
open(init_path, "w").close()
|
|
|
|
with open(writer.path, "w") as fh:
|
|
|
|
fh.write(writer.as_string())
|