Project

General

Profile

Statistics
| Branch: | Revision:

root / env / lib / python2.7 / site-packages / south / management / commands / datamigration.py @ d1a4905f

History | View | Annotate | Download (4.4 KB)

1
"""
2
Data migration creation command
3
"""
4

    
5
import sys
6
import os
7
import re
8
from optparse import make_option
9

    
10
try:
11
    set
12
except NameError:
13
    from sets import Set as set
14

    
15
from django.core.management.base import BaseCommand
16
from django.core.management.color import no_style
17
from django.db import models
18
from django.conf import settings
19

    
20
from south.migration import Migrations
21
from south.exceptions import NoMigrations
22
from south.creator import freezer
23

    
24
class Command(BaseCommand):
25
    option_list = BaseCommand.option_list + (
26
        make_option('--freeze', action='append', dest='freeze_list', type='string',
27
            help='Freeze the specified app(s). Provide an app name with each; use the option multiple times for multiple apps'),
28
        make_option('--stdout', action='store_true', dest='stdout', default=False,
29
            help='Print the migration to stdout instead of writing it to a file.'),
30
    )
31
    help = "Creates a new template data migration for the given app"
32
    usage_str = "Usage: ./manage.py datamigration appname migrationname [--stdout] [--freeze appname]"
33
    
34
    def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options):
35
        
36
        # Any supposed lists that are None become empty lists
37
        freeze_list = freeze_list or []
38

    
39
        # --stdout means name = -
40
        if stdout:
41
            name = "-"
42
        
43
        # Only allow valid names
44
        if re.search('[^_\w]', name) and name != "-":
45
            self.error("Migration names should contain only alphanumeric characters and underscores.")
46
        
47
        # if not name, there's an error
48
        if not name:
49
            self.error("You must provide a name for this migration\n" + self.usage_str)
50
        
51
        if not app:
52
            self.error("You must provide an app to create a migration for.\n" + self.usage_str)
53
        
54
        # Get the Migrations for this app (creating the migrations dir if needed)
55
        migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0)
56
        
57
        # See what filename is next in line. We assume they use numbers.
58
        new_filename = migrations.next_filename(name)
59
        
60
        # Work out which apps to freeze
61
        apps_to_freeze = self.calc_frozen_apps(migrations, freeze_list)
62
        
63
        # So, what's in this file, then?
64
        file_contents = MIGRATION_TEMPLATE % {
65
            "frozen_models":  freezer.freeze_apps_to_string(apps_to_freeze),
66
            "complete_apps": apps_to_freeze and "complete_apps = [%s]" % (", ".join(map(repr, apps_to_freeze))) or ""
67
        }
68
        
69
        # - is a special name which means 'print to stdout'
70
        if name == "-":
71
            print file_contents
72
        # Write the migration file if the name isn't -
73
        else:
74
            fp = open(os.path.join(migrations.migrations_dir(), new_filename), "w")
75
            fp.write(file_contents)
76
            fp.close()
77
            print >>sys.stderr, "Created %s." % new_filename
78
    
79
    def calc_frozen_apps(self, migrations, freeze_list):
80
        """
81
        Works out, from the current app, settings, and the command line options,
82
        which apps should be frozen.
83
        """
84
        apps_to_freeze = []
85
        for to_freeze in freeze_list:
86
            if "." in to_freeze:
87
                self.error("You cannot freeze %r; you must provide an app label, like 'auth' or 'books'." % to_freeze)
88
            # Make sure it's a real app
89
            if not models.get_app(to_freeze):
90
                self.error("You cannot freeze %r; it's not an installed app." % to_freeze)
91
            # OK, it's fine
92
            apps_to_freeze.append(to_freeze)
93
        if getattr(settings, 'SOUTH_AUTO_FREEZE_APP', True):
94
            apps_to_freeze.append(migrations.app_label())
95
        return apps_to_freeze
96
    
97
    def error(self, message, code=1):
98
        """
99
        Prints the error, and exits with the given code.
100
        """
101
        print >>sys.stderr, message
102
        sys.exit(code)
103

    
104

    
105
MIGRATION_TEMPLATE = """# -*- coding: utf-8 -*-
106
import datetime
107
from south.db import db
108
from south.v2 import DataMigration
109
from django.db import models
110

111
class Migration(DataMigration):
112

113
    def forwards(self, orm):
114
        "Write your forwards methods here."
115
        # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..."
116

117
    def backwards(self, orm):
118
        "Write your backwards methods here."
119

120
    models = %(frozen_models)s
121

122
    %(complete_apps)s
123
    symmetrical = True
124
"""