Skip to content

Commit 73f3ce0

Browse files
committed
Replace South with South 0.8.4
- Legacy-Id: 6872
1 parent 1654988 commit 73f3ce0

69 files changed

Lines changed: 4034 additions & 1011 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

south/.gitignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

south/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
South - Useable migrations for Django apps
33
"""
44

5-
__version__ = "0.7.3"
5+
__version__ = "0.8.4"
66
__authors__ = [
77
"Andrew Godwin <andrew@aeracode.org>",
88
"Andy McCurdy <andy@andymccurdy.com>"

south/creator/actions.py

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
blocks into the forwards() and backwards() methods, in the right place.
55
"""
66

7+
from __future__ import print_function
8+
79
import sys
8-
import datetime
910

1011
from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
1112
from django.db.models.fields import FieldDoesNotExist, NOT_PROVIDED, CharField, TextField
1213

13-
from south import modelsinspector
14+
from south.modelsinspector import value_clean
1415
from south.creator.freezer import remove_useless_attributes, model_key
16+
from south.utils import datetime_utils
17+
from south.utils.py3 import raw_input
18+
1519

1620
class Action(object):
1721
"""
@@ -70,11 +74,11 @@ class AddModel(Action):
7074
db.create_table(%(table_name)r, (
7175
%(field_defs)s
7276
))
73-
db.send_create_signal(%(app_label)r, [%(model_name)r])'''
77+
db.send_create_signal(%(app_label)r, [%(model_name)r])'''[1:] + "\n"
7478

7579
BACKWARDS_TEMPLATE = '''
7680
# Deleting model '%(model_name)s'
77-
db.delete_table(%(table_name)r)'''
81+
db.delete_table(%(table_name)r)'''[1:] + "\n"
7882

7983
def __init__(self, model, model_def):
8084
self.model = model
@@ -133,63 +137,65 @@ class _NullIssuesField(object):
133137
A field that might need to ask a question about rogue NULL values.
134138
"""
135139

136-
allow_third_null_option = False
140+
issue_with_backward_migration = False
137141
irreversible = False
138142

139143
IRREVERSIBLE_TEMPLATE = '''
140144
# User chose to not deal with backwards NULL issues for '%(model_name)s.%(field_name)s'
141-
raise RuntimeError("Cannot reverse this migration. '%(model_name)s.%(field_name)s' and its values cannot be restored.")'''
145+
raise RuntimeError("Cannot reverse this migration. '%(model_name)s.%(field_name)s' and its values cannot be restored.")
146+
147+
# The following code is provided here to aid in writing a correct migration'''
142148

143149
def deal_with_not_null_no_default(self, field, field_def):
144150
# If it's a CharField or TextField that's blank, skip this step.
145151
if isinstance(field, (CharField, TextField)) and field.blank:
146152
field_def[2]['default'] = repr("")
147153
return
148154
# Oh dear. Ask them what to do.
149-
print " ? The field '%s.%s' does not have a default specified, yet is NOT NULL." % (
155+
print(" ? The field '%s.%s' does not have a default specified, yet is NOT NULL." % (
150156
self.model._meta.object_name,
151157
field.name,
152-
)
153-
print " ? Since you are %s, you MUST specify a default" % self.null_reason
154-
print " ? value to use for existing rows. Would you like to:"
155-
print " ? 1. Quit now, and add a default to the field in models.py"
156-
print " ? 2. Specify a one-off value to use for existing columns now"
157-
if self.allow_third_null_option:
158-
print " ? 3. Disable the backwards migration by raising an exception."
158+
))
159+
print(" ? Since you are %s, you MUST specify a default" % self.null_reason)
160+
print(" ? value to use for existing rows. Would you like to:")
161+
print(" ? 1. Quit now"+("." if self.issue_with_backward_migration else ", and add a default to the field in models.py" ))
162+
print(" ? 2. Specify a one-off value to use for existing columns now")
163+
if self.issue_with_backward_migration:
164+
print(" ? 3. Disable the backwards migration by raising an exception; you can edit the migration to fix it later")
159165
while True:
160166
choice = raw_input(" ? Please select a choice: ")
161167
if choice == "1":
162168
sys.exit(1)
163169
elif choice == "2":
164170
break
165-
elif choice == "3" and self.allow_third_null_option:
171+
elif choice == "3" and self.issue_with_backward_migration:
166172
break
167173
else:
168-
print " ! Invalid choice."
174+
print(" ! Invalid choice.")
169175
if choice == "2":
170176
self.add_one_time_default(field, field_def)
171177
elif choice == "3":
172178
self.irreversible = True
173179

174180
def add_one_time_default(self, field, field_def):
175181
# OK, they want to pick their own one-time default. Who are we to refuse?
176-
print " ? Please enter Python code for your one-off default value."
177-
print " ? The datetime module is available, so you can do e.g. datetime.date.today()"
182+
print(" ? Please enter Python code for your one-off default value.")
183+
print(" ? The datetime module is available, so you can do e.g. datetime.date.today()")
178184
while True:
179185
code = raw_input(" >>> ")
180186
if not code:
181-
print " ! Please enter some code, or 'exit' (with no quotes) to exit."
187+
print(" ! Please enter some code, or 'exit' (with no quotes) to exit.")
182188
elif code == "exit":
183189
sys.exit(1)
184190
else:
185191
try:
186-
result = eval(code, {}, {"datetime": datetime})
187-
except (SyntaxError, NameError), e:
188-
print " ! Invalid input: %s" % e
192+
result = eval(code, {}, {"datetime": datetime_utils})
193+
except (SyntaxError, NameError) as e:
194+
print(" ! Invalid input: %s" % e)
189195
else:
190196
break
191197
# Right, add the default in.
192-
field_def[2]['default'] = repr(result)
198+
field_def[2]['default'] = value_clean(result)
193199

194200
def irreversable_code(self, field):
195201
return self.IRREVERSIBLE_TEMPLATE % {
@@ -209,11 +215,13 @@ class AddField(Action, _NullIssuesField):
209215

210216
FORWARDS_TEMPLATE = '''
211217
# Adding field '%(model_name)s.%(field_name)s'
212-
db.add_column(%(table_name)r, %(field_name)r, %(field_def)s, keep_default=False)'''
218+
db.add_column(%(table_name)r, %(field_name)r,
219+
%(field_def)s,
220+
keep_default=False)'''[1:] + "\n"
213221

214222
BACKWARDS_TEMPLATE = '''
215223
# Deleting field '%(model_name)s.%(field_name)s'
216-
db.delete_column(%(table_name)r, %(field_column)r)'''
224+
db.delete_column(%(table_name)r, %(field_column)r)'''[1:] + "\n"
217225

218226
def __init__(self, model, field, field_def):
219227
self.model = model
@@ -260,7 +268,7 @@ class DeleteField(AddField):
260268
"""
261269

262270
null_reason = "removing this field"
263-
allow_third_null_option = True
271+
issue_with_backward_migration = True
264272

265273
def console_line(self):
266274
"Returns the string to print on the console, e.g. ' + Added field foo'"
@@ -277,7 +285,7 @@ def backwards_code(self):
277285
if not self.irreversible:
278286
return AddField.forwards_code(self)
279287
else:
280-
return self.irreversable_code(self.field)
288+
return self.irreversable_code(self.field) + AddField.forwards_code(self)
281289

282290

283291
class ChangeField(Action, _NullIssuesField):
@@ -309,7 +317,7 @@ def __init__(self, model, old_field, new_field, old_def, new_def):
309317
self.deal_with_not_null_no_default(self.new_field, self.new_def)
310318
if not self.old_field.null and self.new_field.null and not old_default:
311319
self.null_reason = "making this field nullable"
312-
self.allow_third_null_option = True
320+
self.issue_with_backward_migration = True
313321
self.deal_with_not_null_no_default(self.old_field, self.old_def)
314322

315323
def console_line(self):
@@ -347,10 +355,11 @@ def forwards_code(self):
347355
return self._code(self.old_field, self.new_field, self.new_def)
348356

349357
def backwards_code(self):
358+
change_code = self._code(self.new_field, self.old_field, self.old_def)
350359
if not self.irreversible:
351-
return self._code(self.new_field, self.old_field, self.old_def)
360+
return change_code
352361
else:
353-
return self.irreversable_code(self.old_field)
362+
return self.irreversable_code(self.old_field) + change_code
354363

355364

356365
class AddUnique(Action):
@@ -360,11 +369,11 @@ class AddUnique(Action):
360369

361370
FORWARDS_TEMPLATE = '''
362371
# Adding unique constraint on '%(model_name)s', fields %(field_names)s
363-
db.create_unique(%(table_name)r, %(fields)r)'''
372+
db.create_unique(%(table_name)r, %(fields)r)'''[1:] + "\n"
364373

365374
BACKWARDS_TEMPLATE = '''
366375
# Removing unique constraint on '%(model_name)s', fields %(field_names)s
367-
db.delete_unique(%(table_name)r, %(fields)r)'''
376+
db.delete_unique(%(table_name)r, %(fields)r)'''[1:] + "\n"
368377

369378
prepend_backwards = True
370379

@@ -428,11 +437,11 @@ class AddIndex(AddUnique):
428437

429438
FORWARDS_TEMPLATE = '''
430439
# Adding index on '%(model_name)s', fields %(field_names)s
431-
db.create_index(%(table_name)r, %(fields)r)'''
440+
db.create_index(%(table_name)r, %(fields)r)'''[1:] + "\n"
432441

433442
BACKWARDS_TEMPLATE = '''
434443
# Removing index on '%(model_name)s', fields %(field_names)s
435-
db.delete_index(%(table_name)r, %(fields)r)'''
444+
db.delete_index(%(table_name)r, %(fields)r)'''[1:] + "\n"
436445

437446
def console_line(self):
438447
"Returns the string to print on the console, e.g. ' + Added field foo'"
@@ -470,16 +479,17 @@ class AddM2M(Action):
470479

471480
FORWARDS_TEMPLATE = '''
472481
# Adding M2M table for field %(field_name)s on '%(model_name)s'
473-
db.create_table(%(table_name)r, (
482+
m2m_table_name = %(table_name)s
483+
db.create_table(m2m_table_name, (
474484
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
475485
(%(left_field)r, models.ForeignKey(orm[%(left_model_key)r], null=False)),
476486
(%(right_field)r, models.ForeignKey(orm[%(right_model_key)r], null=False))
477487
))
478-
db.create_unique(%(table_name)r, [%(left_column)r, %(right_column)r])'''
488+
db.create_unique(m2m_table_name, [%(left_column)r, %(right_column)r])'''[1:] + "\n"
479489

480490
BACKWARDS_TEMPLATE = '''
481491
# Removing M2M table for field %(field_name)s on '%(model_name)s'
482-
db.delete_table('%(table_name)s')'''
492+
db.delete_table(%(table_name)s)'''[1:] + "\n"
483493

484494
def __init__(self, model, field):
485495
self.model = model
@@ -492,13 +502,25 @@ def console_line(self):
492502
self.model._meta.app_label,
493503
self.model._meta.object_name,
494504
)
495-
505+
506+
def table_name(self):
507+
# This is part of a workaround for the fact that Django uses
508+
# different shortening for automatically generated m2m table names
509+
# (as opposed to any explicitly specified table name)
510+
f = self.field
511+
explicit = f.db_table
512+
if explicit:
513+
return "%r" % explicit
514+
else:
515+
auto = "%s_%s" % (self.model._meta.db_table, f.name)
516+
return 'db.shorten_name(%r)' % auto
517+
496518
def forwards_code(self):
497519

498520
return self.FORWARDS_TEMPLATE % {
499521
"model_name": self.model._meta.object_name,
500522
"field_name": self.field.name,
501-
"table_name": self.field.m2m_db_table(),
523+
"table_name": self.table_name(),
502524
"left_field": self.field.m2m_column_name()[:-3], # Remove the _id part
503525
"left_column": self.field.m2m_column_name(),
504526
"left_model_key": model_key(self.model),
@@ -512,7 +534,7 @@ def backwards_code(self):
512534
return self.BACKWARDS_TEMPLATE % {
513535
"model_name": self.model._meta.object_name,
514536
"field_name": self.field.name,
515-
"table_name": self.field.m2m_db_table(),
537+
"table_name": self.table_name(),
516538
}
517539

518540

0 commit comments

Comments
 (0)