~ubuntuone-hackers/django-south/trunk

« back to all changes in this revision

Viewing changes to south/creator/actions.py

  • Committer: Ricardo Kirkner
  • Date: 2013-06-10 00:19:31 UTC
  • Revision ID: ricardo.kirkner@canonical.com-20130610001931-azfj57kme0qd4uca
Tags: 0.8
added South-0.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
blocks into the forwards() and backwards() methods, in the right place.
5
5
"""
6
6
 
 
7
from __future__ import print_function
 
8
 
7
9
import sys
8
10
 
9
11
from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
12
14
from south.modelsinspector import value_clean
13
15
from south.creator.freezer import remove_useless_attributes, model_key
14
16
from south.utils import datetime_utils
 
17
from south.utils.py3 import raw_input
15
18
 
16
19
 
17
20
class Action(object):
147
150
            field_def[2]['default'] = repr("")
148
151
            return
149
152
        # Oh dear. Ask them what to do.
150
 
        print " ? The field '%s.%s' does not have a default specified, yet is NOT NULL." % (
 
153
        print(" ? The field '%s.%s' does not have a default specified, yet is NOT NULL." % (
151
154
            self.model._meta.object_name,
152
155
            field.name,
153
 
        )
154
 
        print " ? Since you are %s, you MUST specify a default" % self.null_reason
155
 
        print " ? value to use for existing rows. Would you like to:"
156
 
        print " ?  1. Quit now, and add a default to the field in models.py"
157
 
        print " ?  2. Specify a one-off value to use for existing columns now"
 
156
        ))
 
157
        print(" ? Since you are %s, you MUST specify a default" % self.null_reason)
 
158
        print(" ? value to use for existing rows. Would you like to:")
 
159
        print(" ?  1. Quit now, and add a default to the field in models.py")
 
160
        print(" ?  2. Specify a one-off value to use for existing columns now")
158
161
        if self.allow_third_null_option:
159
 
            print " ?  3. Disable the backwards migration by raising an exception."
 
162
            print(" ?  3. Disable the backwards migration by raising an exception.")
160
163
        while True:
161
164
            choice = raw_input(" ? Please select a choice: ")
162
165
            if choice == "1":
166
169
            elif choice == "3" and self.allow_third_null_option:
167
170
                break
168
171
            else:
169
 
                print " ! Invalid choice."
 
172
                print(" ! Invalid choice.")
170
173
        if choice == "2":
171
174
            self.add_one_time_default(field, field_def)
172
175
        elif choice == "3":
174
177
 
175
178
    def add_one_time_default(self, field, field_def):
176
179
        # OK, they want to pick their own one-time default. Who are we to refuse?
177
 
        print " ? Please enter Python code for your one-off default value."
178
 
        print " ? The datetime module is available, so you can do e.g. datetime.date.today()"
 
180
        print(" ? Please enter Python code for your one-off default value.")
 
181
        print(" ? The datetime module is available, so you can do e.g. datetime.date.today()")
179
182
        while True:
180
183
            code = raw_input(" >>> ")
181
184
            if not code:
182
 
                print " ! Please enter some code, or 'exit' (with no quotes) to exit."
 
185
                print(" ! Please enter some code, or 'exit' (with no quotes) to exit.")
183
186
            elif code == "exit":
184
187
                sys.exit(1)
185
188
            else:
186
189
                try:
187
190
                    result = eval(code, {}, {"datetime": datetime_utils})
188
 
                except (SyntaxError, NameError), e:
189
 
                    print " ! Invalid input: %s" % e
 
191
                except (SyntaxError, NameError) as e:
 
192
                    print(" ! Invalid input: %s" % e)
190
193
                else:
191
194
                    break
192
195
        # Right, add the default in.
473
476
    
474
477
    FORWARDS_TEMPLATE = '''
475
478
        # Adding M2M table for field %(field_name)s on '%(model_name)s'
476
 
        db.create_table(%(table_name)r, (
 
479
        m2m_table_name = %(table_name)s
 
480
        db.create_table(m2m_table_name, (
477
481
            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
478
482
            (%(left_field)r, models.ForeignKey(orm[%(left_model_key)r], null=False)),
479
483
            (%(right_field)r, models.ForeignKey(orm[%(right_model_key)r], null=False))
480
484
        ))
481
 
        db.create_unique(%(table_name)r, [%(left_column)r, %(right_column)r])'''[1:] + "\n"
 
485
        db.create_unique(m2m_table_name, [%(left_column)r, %(right_column)r])'''[1:] + "\n"
482
486
    
483
487
    BACKWARDS_TEMPLATE = '''
484
488
        # Removing M2M table for field %(field_name)s on '%(model_name)s'
485
 
        db.delete_table('%(table_name)s')'''[1:] + "\n"
 
489
        db.delete_table(%(table_name)s)'''[1:] + "\n"
486
490
    
487
491
    def __init__(self, model, field):
488
492
        self.model = model
495
499
            self.model._meta.app_label, 
496
500
            self.model._meta.object_name,
497
501
        )
498
 
    
 
502
 
 
503
    def table_name(self):
 
504
        # This is part of a workaround for the fact that Django uses
 
505
        # different shortening for automatically generated m2m table names 
 
506
        # (as opposed to any explicitly specified table name)
 
507
        f = self.field
 
508
        explicit = f.db_table
 
509
        if explicit:
 
510
            return "%r" % explicit
 
511
        else:
 
512
            auto = "%s_%s" % (self.model._meta.db_table, f.name)
 
513
            return 'db.shorten_name(%r)' % auto
 
514
 
499
515
    def forwards_code(self):
500
516
        
501
517
        return self.FORWARDS_TEMPLATE % {
502
518
            "model_name": self.model._meta.object_name,
503
519
            "field_name": self.field.name,
504
 
            "table_name": self.field.m2m_db_table(),
 
520
            "table_name": self.table_name(),
505
521
            "left_field": self.field.m2m_column_name()[:-3], # Remove the _id part
506
522
            "left_column": self.field.m2m_column_name(),
507
523
            "left_model_key": model_key(self.model),
515
531
        return self.BACKWARDS_TEMPLATE % {
516
532
            "model_name": self.model._meta.object_name,
517
533
            "field_name": self.field.name,
518
 
            "table_name": self.field.m2m_db_table(),
 
534
            "table_name": self.table_name(),
519
535
        }
520
536
 
521
537