1. Artem Pahomov
  2. DjangoBB

Commits

Sergey Maranchuk  committed e6f4ca6

remove django_evolution from repo

  • Participants
  • Parent commits 6431110
  • Branches default

Comments (0)

Files changed (18)

File django_evolution/__init__.py

  • Ignore whitespace
-class EvolutionException(Exception):
-    def __init__(self,msg):
-        self.msg = msg
-
-    def __str__(self):
-        return str(self.msg)
-        
-class CannotSimulate(EvolutionException):
-    pass
-    
-class SimulationFailure(EvolutionException):
-    pass
-
-class EvolutionNotImplementedError(EvolutionException, NotImplementedError):
-    pass

File django_evolution/admin.py

  • Ignore whitespace
-from django.contrib import admin
-from django_evolution.models import Version, Evolution
-
-admin.site.register(Version)
-admin.site.register(Evolution)

File django_evolution/db/__init__.py

  • Ignore whitespace
-# Establish the common EvolutionOperations instance, called evolver.
-
-from django.conf import settings
-
-module_name = ['django_evolution.db',settings.DATABASE_ENGINE]
-module = __import__('.'.join(module_name),{},{},[''])
-
-evolver = module.EvolutionOperations()
-

File django_evolution/db/common.py

  • Ignore whitespace
-from django.core.management import color
-from django.db import connection, models
-import copy
-
-class BaseEvolutionOperations(object):
-    def quote_sql_param(self, param):
-        "Add protective quoting around an SQL string parameter"
-        if isinstance(param, basestring):
-            return u"'%s'" % unicode(param).replace(u"'",ur"\'")
-        else:
-            return param
-
-    def rename_table(self, old_db_tablename, db_tablename):
-        if old_db_tablename == db_tablename:
-            # No Operation
-            return []
-    
-        qn = connection.ops.quote_name
-        params = (qn(old_db_tablename), qn(db_tablename))
-        return ['ALTER TABLE %s RENAME TO %s;' % params]
-    
-    def delete_column(self, model, f):
-        qn = connection.ops.quote_name
-        params = (qn(model._meta.db_table), qn(f.column))
-    
-        return ['ALTER TABLE %s DROP COLUMN %s CASCADE;' % params]
-
-    def delete_table(self, table_name):
-        qn = connection.ops.quote_name
-        return ['DROP TABLE %s;' % qn(table_name)]
-    
-    def add_m2m_table(self, model, f):
-        final_output = []
-        qn = connection.ops.quote_name
-        opts = model._meta
-        style = color.no_style()
-    
-        return connection.creation.sql_for_many_to_many_field(model, f, style)
-    
-    def add_column(self, model, f, initial):
-        qn = connection.ops.quote_name
-    
-        if f.rel:
-            # it is a foreign key field
-            # NOT NULL REFERENCES "django_evolution_addbasemodel" ("id") DEFERRABLE INITIALLY DEFERRED
-            # ALTER TABLE <tablename> ADD COLUMN <column name> NULL REFERENCES <tablename1> ("<colname>") DEFERRABLE INITIALLY DEFERRED
-            related_model = f.rel.to
-            related_table = related_model._meta.db_table
-            related_pk_col = related_model._meta.pk.name
-            constraints = ['%sNULL' % (not f.null and 'NOT ' or '')]
-            if f.unique or f.primary_key:
-                constraints.append('UNIQUE')
-            params = (qn(model._meta.db_table), qn(f.column), f.db_type(), ' '.join(constraints), 
-                qn(related_table), qn(related_pk_col), connection.ops.deferrable_sql())
-            output = ['ALTER TABLE %s ADD COLUMN %s %s %s REFERENCES %s (%s) %s;' % params]
-        else:
-            null_constraints = '%sNULL' % (not f.null and 'NOT ' or '')
-            if f.unique or f.primary_key:
-                unique_constraints = 'UNIQUE'
-            else:
-                unique_constraints = ''
-
-            # At this point, initial can only be None if null=True, otherwise it is 
-            # a user callable or the default AddFieldInitialCallback which will shortly raise an exception.
-            if initial is not None:
-                params = (qn(model._meta.db_table), qn(f.column), f.db_type(), unique_constraints)
-                output = ['ALTER TABLE %s ADD COLUMN %s %s %s;' % params]
-            
-                if callable(initial):
-                    params = (qn(model._meta.db_table), qn(f.column), initial(), qn(f.column))
-                    output.append('UPDATE %s SET %s = %s WHERE %s IS NULL;' % params)
-                else:
-                    params = (qn(model._meta.db_table), qn(f.column), qn(f.column))
-                    output.append(('UPDATE %s SET %s = %%s WHERE %s IS NULL;' % params, (initial,)))
-            
-                if not f.null:
-                    # Only put this sql statement if the column cannot be null.
-                    output.append(self.set_field_null(model, f, f.null))
-            else:
-                params = (qn(model._meta.db_table), qn(f.column), f.db_type(),' '.join([null_constraints, unique_constraints]))
-                output = ['ALTER TABLE %s ADD COLUMN %s %s %s;' % params]
-        return output
-
-    def set_field_null(self, model, f, null):
-        qn = connection.ops.quote_name
-        params = (qn(model._meta.db_table), qn(f.column),)
-        if null:
-           return 'ALTER TABLE %s ALTER COLUMN %s DROP NOT NULL;' % params
-        else:
-            return 'ALTER TABLE %s ALTER COLUMN %s SET NOT NULL;' % params 
-    
-    def create_index(self, model, f):
-        "Returns the CREATE INDEX SQL statements."
-        output = []
-        qn = connection.ops.quote_name
-        style = color.no_style()
-    
-        return connection.creation.sql_indexes_for_field(model, f, style)
-        
-    def drop_index(self, model, f):
-        qn = connection.ops.quote_name
-        return ['DROP INDEX %s;' % qn(self.get_index_name(model, f))]
-        
-    def get_index_name(self, model, f):
-        return '%s_%s' % (model._meta.db_table, f.column)
-        
-    def change_null(self, model, field_name, new_null_attr, initial=None):
-        qn = connection.ops.quote_name
-        opts = model._meta
-        f = opts.get_field(field_name)
-        output = []
-        if new_null_attr:
-            # Setting null to True
-            opts = model._meta
-            params = (qn(opts.db_table), qn(f.column),)
-            output.append(self.set_field_null(model, f, new_null_attr))
-        else:
-            if initial is not None:
-                output = []
-                if callable(initial):
-                    params = (qn(opts.db_table), qn(f.column), initial(), qn(f.column))
-                    output.append('UPDATE %s SET %s = %s WHERE %s IS NULL;' % params)
-                else:
-                    params = (qn(opts.db_table), qn(f.column), qn(f.column))
-                    output.append(('UPDATE %s SET %s = %%s WHERE %s IS NULL;' % params, (initial,)))
-            output.append(self.set_field_null(model, f, new_null_attr))
-            
-        return output
-        
-    def change_max_length(self, model, field_name, new_max_length, initial=None):
-        qn = connection.ops.quote_name
-        opts = model._meta
-        f = opts.get_field(field_name)
-        f.max_length = new_max_length
-        params = (qn(opts.db_table), qn(f.column), f.db_type(), qn(f.column), f.db_type())
-        return ['ALTER TABLE %s ALTER COLUMN %s TYPE %s USING CAST(%s as %s);' % params]
-
-    def change_db_column(self, model, field_name, new_db_column, initial=None):
-        opts = model._meta
-        old_field = opts.get_field(field_name)
-        new_field = copy.copy(old_field)
-        new_field.column = new_db_column
-        return self.rename_column(opts, old_field, new_field)
-
-    def change_db_table(self, old_db_tablename, new_db_tablename):
-        return self.rename_table(old_db_tablename, new_db_tablename)
-        
-    def change_db_index(self, model, field_name, new_db_index, initial=None):
-        f = model._meta.get_field(field_name)
-        f.db_index = new_db_index
-        if new_db_index:
-            return self.create_index(model, f)
-        else:
-            return self.drop_index(model, f)
-            
-    def change_unique(self, model, field_name, new_unique_value, initial=None):
-        qn = connection.ops.quote_name
-        opts = model._meta
-        f = opts.get_field(field_name)
-        constraint_name = '%s_%s_key' % (opts.db_table, f.column,)
-        if new_unique_value:
-            params = (qn(opts.db_table), constraint_name, qn(f.column),)
-            return ['ALTER TABLE %s ADD CONSTRAINT %s UNIQUE(%s);' % params]
-        else:
-            params = (qn(opts.db_table), constraint_name,)
-            return ['ALTER TABLE %s DROP CONSTRAINT %s;' % params]

File django_evolution/db/mysql.py

  • Ignore whitespace
-from django.core.management import color
-from django.db import connection
-
-from common import BaseEvolutionOperations
-
-class EvolutionOperations(BaseEvolutionOperations):
-    def rename_column(self, opts, old_field, f):
-        if old_field.column == f.column:
-            # No Operation
-            return []
-    
-        qn = connection.ops.quote_name
-        style = color.no_style()
-    
-        ###
-        col_type = f.db_type()
-        tablespace = f.db_tablespace or opts.db_tablespace
-        if col_type is None:
-            # Skip ManyToManyFields, because they're not represented as
-            # database columns in this table.
-            return []
-        # Make the definition (e.g. 'foo VARCHAR(30)') for this field.
-        field_output = [style.SQL_FIELD(qn(f.column)),
-            style.SQL_COLTYPE(col_type)]
-        field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
-        if f.primary_key:
-            field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
-        if f.unique:
-            field_output.append(style.SQL_KEYWORD('UNIQUE'))
-        if tablespace and connection.features.supports_tablespaces and (f.unique or f.primary_key) and connection.features.autoindexes_primary_keys:
-            # We must specify the index tablespace inline, because we
-            # won't be generating a CREATE INDEX statement for this field.
-            field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
-        if f.rel:
-            field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
-                style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
-                style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
-                connection.ops.deferrable_sql()
-            )
-        
-        params = (qn(opts.db_table), qn(old_field.column), ' '.join(field_output))
-        return ['ALTER TABLE %s CHANGE COLUMN %s %s;' % params]
-
-    def set_field_null(self, model, f, null):
-        qn = connection.ops.quote_name
-        params = (qn(model._meta.db_table), qn(f.column), f.db_type())
-        if null:
-            return 'ALTER TABLE %s MODIFY COLUMN %s %s DEFAULT NULL;' % params
-        else:
-            return 'ALTER TABLE %s MODIFY COLUMN %s %s NOT NULL;' % params
-
-    def change_max_length(self, model, field_name, new_max_length, initial=None):
-        qn = connection.ops.quote_name
-        opts = model._meta
-        f = opts.get_field(field_name)
-        f.max_length = new_max_length
-        params = {
-            'table': qn(opts.db_table),
-            'column': qn(f.column), 
-            'length': f.max_length, 
-            'type': f.db_type()
-        }
-        return ['UPDATE %(table)s SET %(column)s=LEFT(%(column)s,%(length)d);' % params,
-                'ALTER TABLE %(table)s MODIFY COLUMN %(column)s %(type)s;' % params]
-
-    def drop_index(self, model, f):
-        qn = connection.ops.quote_name
-        params = (qn(self.get_index_name(model, f)), qn(model._meta.db_table))
-        return ['DROP INDEX %s ON %s;' % params]
-
-    def change_unique(self, model, field_name, new_unique_value, initial=None):
-        qn = connection.ops.quote_name
-        opts = model._meta
-        f = opts.get_field(field_name)
-        constraint_name = '%s' % (f.column,)
-        if new_unique_value:
-            params = (constraint_name, qn(opts.db_table), qn(f.column),)
-            return ['CREATE UNIQUE INDEX %s ON %s(%s);' % params]
-        else:
-            params = (constraint_name, qn(opts.db_table))
-            return ['DROP INDEX %s ON %s;' % params]
-
-    def rename_table(self, old_db_tablename, db_tablename):
-        if old_db_tablename == db_tablename:
-            return []
-        
-        qn = connection.ops.quote_name
-        params = (qn(old_db_tablename), qn(db_tablename))
-        return ['RENAME TABLE %s TO %s;' % params]

File django_evolution/db/mysql_old.py

  • Ignore whitespace
-# MySQL_old behaviour is identical to mysql base
-from mysql import *

File django_evolution/db/postgresql.py

  • Ignore whitespace
-from django.db import connection
-
-from common import BaseEvolutionOperations
-
-class EvolutionOperations(BaseEvolutionOperations):
-    def rename_column(self, opts, old_field, new_field):
-        if old_field.column == new_field.column:
-            # No Operation
-            return []
-    
-        qn = connection.ops.quote_name
-        params = (qn(opts.db_table), qn(old_field.column), qn(new_field.column))
-        return ['ALTER TABLE %s RENAME COLUMN %s TO %s;' % params]
-    

File django_evolution/db/postgresql_psycopg2.py

  • Ignore whitespace
-# Psycopg2 behaviour is identical to Psycopg1
-from postgresql import *

File django_evolution/db/sqlite3.py

  • Ignore whitespace
-from django.core.management import color
-from django.db import connection, models
-
-from common import BaseEvolutionOperations
-
-TEMP_TABLE_NAME = 'TEMP_TABLE'
-
-class EvolutionOperations(BaseEvolutionOperations):
-    def delete_column(self, model, f):
-        qn = connection.ops.quote_name
-        output = []
-    
-        field_list = [field for field in model._meta.local_fields
-                        if f.name != field.name # Remove the field to be deleted
-                        and field.db_type() is not None] # and any Generic fields
-        table_name = model._meta.db_table
-    
-        output.extend(self.create_temp_table(field_list))
-        output.extend(self.copy_to_temp_table(table_name, field_list))
-        output.extend(self.delete_table(table_name))
-        output.extend(self.create_table(table_name, field_list))
-        output.extend(self.copy_from_temp_table(table_name, field_list))
-        output.extend(self.delete_table(TEMP_TABLE_NAME))
-    
-        return output
-    
-    def create_mock_model(self, model, fields):
-        field_sig_dict = {}
-        for f in fields:
-            field_sig_dict[f.name] = create_field_sig(field)
-    
-        proj_sig = create_project_sig()
-        model_sig = create_model_sig(model)
-        model_sig['fields'] = field_sig_dict
-        mock_model = MockModel(proj_sig, model.app_name, model.model_name, model_sig, stub=False)
-        
-    def copy_to_temp_table(self, source_table_name, field_list):
-        qn = connection.ops.quote_name
-        output = [self.create_temp_table(field_list)]
-        columns = []
-        for field in field_list:
-            if not models.ManyToManyField == field.__class__:
-                columns.append(qn(field.column))
-        column_names = ', '.join(columns)
-        return ['INSERT INTO %s SELECT %s FROM %s;' % (qn(TEMP_TABLE_NAME), column_names, qn(source_table_name))]
-    
-    def copy_from_temp_table(self, dest_table_name, field_list):
-        qn = connection.ops.quote_name
-        columns = []
-        for field in field_list:
-            if not models.ManyToManyField == field.__class__:
-                columns.append(qn(field.column))
-        column_names = ', '.join(columns)
-        params = {
-            'dest_table_name': qn(dest_table_name),
-            'temp_table': qn(TEMP_TABLE_NAME),
-            'column_names': column_names,
-        }
-    
-        return ['INSERT INTO %(dest_table_name)s (%(column_names)s) SELECT %(column_names)s FROM %(temp_table)s;' % params]
-    
-    def insert_to_temp_table(self, field, initial):
-        qn = connection.ops.quote_name
-    
-        # At this point, initial can only be None if null=True, otherwise it is 
-        # a user callable or the default AddFieldInitialCallback which will shortly raise an exception.
-        if initial is None:
-            return []
-
-        params = {
-            'table_name': qn(TEMP_TABLE_NAME),
-            'column_name': qn(field.column),
-        }
-
-        if callable(initial):
-            params['value'] = initial()
-            return ["UPDATE %(table_name)s SET %(column_name)s = %(value)s;" % params]
-        else:
-            return [("UPDATE %(table_name)s SET %(column_name)s = %%s;" % params, (initial,))]
-        
-
-    def create_temp_table(self, field_list):
-        return self.create_table(TEMP_TABLE_NAME, field_list, True, False)
-
-    def create_indexes_for_table(self, table_name, field_list):
-        class FakeMeta(object):
-            def __init__(self, table_name, field_list):
-                self.db_table = table_name
-                self.local_fields = field_list
-                self.fields = field_list # Required for Pre QS-RF support
-                self.db_tablespace = None
-
-        class FakeModel(object):
-            def __init__(self, table_name, field_list):
-                self._meta = FakeMeta(table_name, field_list)
-
-        style = color.no_style()
-        return connection.creation.sql_indexes_for_model(FakeModel(table_name, field_list), style)
-    
-    def create_table(self, table_name, field_list, temporary=False, create_index=True):
-        qn = connection.ops.quote_name
-        output = []
-    
-        create = ['CREATE']
-        if temporary:
-            create.append('TEMPORARY')
-        create.append('TABLE %s' % qn(table_name))
-        output = [' '.join(create)]
-        output.append('(')
-        columns = []
-        for field in field_list:
-            if not models.ManyToManyField == field.__class__:
-                column_name = qn(field.column)
-                column_type = field.db_type()
-                params = [column_name, column_type]
-                if field.null:
-                    params.append('NULL')
-                else:
-                    params.append('NOT NULL')
-                if field.unique:
-                    params.append('UNIQUE')
-                if field.primary_key:
-                    params.append('PRIMARY KEY')
-                columns.append(' '.join(params))
-
-        output.append(', '.join(columns))
-        output.append(');')
-        output = [''.join(output)]
-    
-        if create_index:
-            output.extend(self.create_indexes_for_table(table_name, field_list))
-
-        return output
-    
-    def rename_column(self, opts, old_field, new_field):
-        if old_field.column == new_field.column:
-            # No Operation
-            return []
-
-        original_fields = opts.local_fields
-        new_fields = []
-        for f in original_fields:
-            if f.db_type() is not None: # Ignore Generic Fields
-                if f.name == old_field.name:
-                    new_fields.append(new_field)
-                else:
-                    new_fields.append(f)
-
-        table_name = opts.db_table
-        output = []
-        output.extend(self.create_temp_table(new_fields))
-        output.extend(self.copy_to_temp_table(table_name, original_fields))
-        output.extend(self.delete_table(table_name))
-        output.extend(self.create_table(table_name, new_fields))
-        output.extend(self.copy_from_temp_table(table_name, new_fields))
-        output.extend(self.delete_table(TEMP_TABLE_NAME))
-    
-        return output
-    
-    def add_column(self, model, f, initial):
-        output = []
-        table_name = model._meta.db_table
-        original_fields = [field for field in model._meta.local_fields if field.db_type() is not None]
-        new_fields = original_fields
-        new_fields.append(f)
-    
-        output.extend(self.create_temp_table(new_fields))
-        output.extend(self.copy_to_temp_table(table_name, original_fields))
-        output.extend(self.insert_to_temp_table(f, initial))
-        output.extend(self.delete_table(table_name))
-        output.extend(self.create_table(table_name, new_fields, create_index=False))
-        output.extend(self.copy_from_temp_table(table_name, new_fields))
-        output.extend(self.delete_table(TEMP_TABLE_NAME))
-        return output
-
-    def change_null(self, model, field_name, new_null_attr, initial=None):
-        return self.change_attribute(model, field_name, 'null', new_null_attr, initial)
-        
-    def change_max_length(self, model, field_name, new_max_length, initial=None):
-        return self.change_attribute(model, field_name, 'max_length', new_max_length, initial)
-        
-    def change_unique(self, model, field_name, new_unique_value, initial=None):
-        return self.change_attribute(model, field_name, '_unique', new_unique_value, initial)
-        
-    def change_attribute(self, model, field_name, attr_name, new_attr_value, initial=None):
-        output = []
-        opts = model._meta
-        table_name = opts.db_table
-        setattr(opts.get_field(field_name), attr_name, new_attr_value)
-        fields = [f for f in opts.local_fields if f.db_type() is not None]
-        
-        output.extend(self.create_temp_table(fields))
-        output.extend(self.copy_to_temp_table(table_name, fields))
-        output.extend(self.insert_to_temp_table(opts.get_field(field_name), initial))
-        output.extend(self.delete_table(table_name))
-        output.extend(self.create_table(table_name, fields, create_index=False))
-        output.extend(self.copy_from_temp_table(table_name, fields))
-        output.extend(self.delete_table(TEMP_TABLE_NAME))
-        return output

File django_evolution/diff.py

  • Ignore whitespace
-from django.db import models
-from django.db.models.fields.related import *
-
-from django_evolution import EvolutionException
-from django_evolution.mutations import DeleteField, AddField, DeleteModel, ChangeField
-from django_evolution.signature import ATTRIBUTE_DEFAULTS
-
-try:
-    set
-except ImportError:
-    from sets import Set as set #Python 2.3 Fallback
-
-class NullFieldInitialCallback(object):
-    def __init__(self, app, model, field):
-        self.app = app
-        self.model = model
-        self.field = field
-
-    def __repr__(self):
-        return '<<USER VALUE REQUIRED>>'
-
-    def __call__(self):
-        raise EvolutionException("Cannot use hinted evolution: AddField or ChangeField mutation for '%s.%s' in '%s' requires user-specified initial value." % (
-                                    self.model, self.field, self.app))
-
-def get_initial_value(app_label, model_name, field_name):
-    """Derive an initial value for a field.
-
-    If a default has been provided on the field definition or the field allows
-    for an empty string, that value will be used. Otherwise, a placeholder
-    callable will be used. This callable cannot actually be used in an
-    evolution, but will indicate that user input is required.
-    """
-    model = models.get_model(app_label, model_name)
-    field = model._meta.get_field(field_name)
-    if field and (field.has_default() or (field.empty_strings_allowed and field.blank)):
-        return field.get_default()
-    return NullFieldInitialCallback(app_label, model_name, field_name)
-
-class Diff(object):
-    """
-    A diff between two model signatures.
-
-    The resulting diff is contained in two attributes:
-
-    self.changed = {
-        app_label: {
-            'changed': {
-                model_name : {
-                    'added': [ list of added field names ]
-                    'deleted': [ list of deleted field names ]
-                    'changed': {
-                        field: [ list of modified property names ]
-                    }
-                }
-            'deleted': [ list of deleted model names ]
-        }
-    }
-    self.deleted = {
-        app_label: [ list of models in deleted app ]
-    }
-    """
-    def __init__(self, original, current):
-        self.original_sig = original
-        self.current_sig = current
-
-        self.changed = {}
-        self.deleted = {}
-
-        if self.original_sig.get('__version__', 1) != 1:
-            raise EvolutionException("Unknown version identifier in original signature: %s",
-                                        self.original_sig['__version__'])
-        if self.current_sig.get('__version__', 1) != 1:
-            raise EvolutionException("Unknown version identifier in target signature: %s",
-                                        self.current_sig['__version__'])
-
-        for app_name, old_app_sig in original.items():
-            if app_name == '__version__':
-                # Ignore the __version__ tag
-                continue
-            new_app_sig = self.current_sig.get(app_name, None)
-            if new_app_sig is None:
-                # App has been deleted
-                self.deleted[app_name] = old_app_sig.keys()
-                continue
-            for model_name, old_model_sig in old_app_sig.items():
-                new_model_sig = new_app_sig.get(model_name, None)
-                if new_model_sig is None:
-                    # Model has been deleted
-                    self.changed.setdefault(app_name,
-                        {}).setdefault('deleted',
-                        []).append(model_name)
-                    continue
-                # Look for deleted or modified fields
-                for field_name,old_field_data in old_model_sig['fields'].items():
-                    new_field_data = new_model_sig['fields'].get(field_name,None)
-                    if new_field_data is None:
-                        # Field has been deleted
-                        self.changed.setdefault(app_name,
-                            {}).setdefault('changed',
-                            {}).setdefault(model_name,
-                            {}).setdefault('deleted',
-                            []).append(field_name)
-                        continue
-                    properties = set(old_field_data.keys())
-                    properties.update(new_field_data.keys())
-                    for prop in properties:
-                        old_value = old_field_data.get(prop,
-                            ATTRIBUTE_DEFAULTS.get(prop, None))
-                        new_value = new_field_data.get(prop,
-                            ATTRIBUTE_DEFAULTS.get(prop, None))
-                        if old_value != new_value:
-                            try:
-                                if (prop == 'field_type' and
-                                    (old_value().get_internal_type() ==
-                                     new_value().get_internal_type())):
-                                    continue
-                            except TypeError:
-                                pass
-
-                            # Field has been changed
-                            self.changed.setdefault(app_name,
-                                {}).setdefault('changed',
-                                {}).setdefault(model_name,
-                                {}).setdefault('changed',
-                                {}).setdefault(field_name,[]).append(prop)
-                # Look for added fields
-                for field_name,new_field_data in new_model_sig['fields'].items():
-                    old_field_data = old_model_sig['fields'].get(field_name,None)
-                    if old_field_data is None:
-                        self.changed.setdefault(app_name,
-                            {}).setdefault('changed',
-                            {}).setdefault(model_name,
-                            {}).setdefault('added',
-                            []).append(field_name)
-
-    def is_empty(self, ignore_apps=True):
-        """Is this an empty diff? i.e., is the source and target the same?
-
-        Set 'ignore_apps=False' if you wish to ignore changes caused by
-        deleted applications. This is used when you don't purge deleted
-        applications during an evolve.
-        """
-        if ignore_apps:
-            return not self.changed
-        else:
-            return not self.deleted and not self.changed
-
-    def __str__(self):
-        "Output an application signature diff in a human-readable format"
-        lines = []
-        for app_label in self.deleted:
-            lines.append('The application %s has been deleted' % app_label)
-        for app_label, app_changes in self.changed.items():
-            for model_name in app_changes.get('deleted', {}):
-                lines.append('The model %s.%s has been deleted' % (app_label, model_name))
-            for model_name, change in app_changes.get('changed', {}).items():
-                lines.append('In model %s.%s:' % (app_label, model_name))
-                for field_name in change.get('added',[]):
-                    lines.append("    Field '%s' has been added" % field_name)
-                for field_name in change.get('deleted',[]):
-                    lines.append("    Field '%s' has been deleted" % field_name)
-                for field_name,field_change in change.get('changed',{}).items():
-                    lines.append("    In field '%s':" % field_name)
-                    for prop in field_change:
-                        lines.append("        Property '%s' has changed" % prop)
-        return '\n'.join(lines)
-
-    def evolution(self):
-        "Generate an evolution that would neutralize the diff"
-        mutations = {}
-        for app_label, app_changes in self.changed.items():
-            for model_name, change in app_changes.get('changed',{}).items():
-                for field_name in change.get('added',{}):
-                    field_sig = self.current_sig[app_label][model_name]['fields'][field_name]
-                    add_params = [(key,field_sig[key])
-                                    for key in field_sig.keys()
-                                    if key in ATTRIBUTE_DEFAULTS.keys()]
-                    add_params.append(('field_type', field_sig['field_type']))
-
-                    if field_sig['field_type'] != models.ManyToManyField and not field_sig.get('null', ATTRIBUTE_DEFAULTS['null']):
-                        add_params.append(('initial', get_initial_value(app_label, model_name, field_name)))
-                    if 'related_model' in field_sig:
-                        add_params.append(('related_model', '%s' % field_sig['related_model']))
-                    mutations.setdefault(app_label,[]).append(
-                        AddField(model_name, field_name, **dict(add_params)))
-                for field_name in change.get('deleted',[]):
-                    mutations.setdefault(app_label,[]).append(
-                        DeleteField(model_name, field_name))
-                for field_name,field_change in change.get('changed',{}).items():
-                    changed_attrs = {}
-                    current_field_sig = self.current_sig[app_label][model_name]['fields'][field_name]
-                    for prop in field_change:
-                        if prop == 'related_model':
-                            changed_attrs[prop] = current_field_sig[prop]
-                        else:
-                            changed_attrs[prop] = current_field_sig.get(prop, ATTRIBUTE_DEFAULTS[prop])
-                    if changed_attrs.has_key('null') and \
-                        current_field_sig['field_type'] != models.ManyToManyField and \
-                        not current_field_sig.get('null', ATTRIBUTE_DEFAULTS['null']):
-                        changed_attrs['initial'] = get_initial_value(app_label, model_name, field_name)
-                    mutations.setdefault(app_label,[]).append(ChangeField(model_name, field_name, **changed_attrs))
-            for model_name in app_changes.get('deleted',{}):
-                mutations.setdefault(app_label,[]).append(DeleteModel(model_name))
-        return mutations

File django_evolution/evolve.py

  • Ignore whitespace
-import os
-import sys
-import copy
-
-from django.core.management.color import color_style
-from django.db import transaction, connection
-from django.db.models import loading
-
-from django_evolution import EvolutionException, CannotSimulate, SimulationFailure
-from django_evolution.models import Evolution
-from django_evolution.diff import Diff
-from django_evolution.mutations import SQLMutation
-
-def get_evolution_sequence(app):
-    "Obtain the full evolution sequence for an application"
-    try:
-        app_name = '.'.join(app.__name__.split('.')[:-1])
-        evolution_module = __import__(app_name + '.evolutions',{},{},[''])
-        return evolution_module.SEQUENCE
-    except:
-        return []
-    
-def get_unapplied_evolutions(app):
-    "Obtain the list of unapplied evolutions for an application"
-    sequence = get_evolution_sequence(app)
-    app_label = app.__name__.split('.')[-2]
-    applied = [evo.label for evo in Evolution.objects.filter(app_label=app_label)]
-    return [seq for seq in sequence if seq not in applied]
-    
-def get_mutations(app, evolution_labels):
-    """
-    Obtain the list of mutations described by the named evolutions.
-    """
-    # For each item in the evolution sequence. Check each item to see if it is
-    # a python file or an sql file.
-    try:
-        app_name = '.'.join(app.__name__.split('.')[:-1])
-        evolution_module = __import__(app_name + '.evolutions',{},{},[''])
-    except ImportError:
-        return []
-
-    mutations = []
-    for label in evolution_labels:
-        directory_name = os.path.dirname(evolution_module.__file__)
-        sql_file_name = os.path.join(directory_name, label+'.sql')
-        if os.path.exists(sql_file_name):
-            sql = []
-            sql_file = open(sql_file_name)
-            for line in sql_file:
-                sql.append(line)
-            mutations.append(SQLMutation(label, sql))
-        else:
-            try:
-                module_name = [evolution_module.__name__,label]
-                module = __import__('.'.join(module_name),{},{},[module_name]);
-                mutations.extend(module.MUTATIONS)
-            except ImportError, e:
-                raise EvolutionException('Error: Failed to find an SQL or Python evolution named %s' % label)
-            
-    return mutations

File django_evolution/management/__init__.py

  • Ignore whitespace
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle as pickle
-
-from django.dispatch import dispatcher
-from django.core.management.color import color_style
-from django.db.models import signals, get_apps
-
-from django_evolution import models as django_evolution
-from django_evolution.evolve import get_evolution_sequence, get_unapplied_evolutions
-from django_evolution.signature import create_project_sig
-from django_evolution.diff import Diff
-
-style = color_style()
-    
-def evolution(app, created_models, verbosity=1, **kwargs):
-    """
-    A hook into syncdb's post_syncdb signal, that is used to notify the user
-    if a model evolution is necessary.
-    """
-    proj_sig = create_project_sig()
-    signature = pickle.dumps(proj_sig)
-
-    try:
-        latest_version = django_evolution.Version.objects.latest('when')
-    except django_evolution.Version.DoesNotExist:
-        # We need to create a baseline version.
-        if verbosity > 0:
-            print "Installing baseline version"
-
-        latest_version = django_evolution.Version(signature=signature)
-        latest_version.save()
-
-        for a in get_apps():
-            app_label = a.__name__.split('.')[-2]
-            sequence = get_evolution_sequence(a)
-            if sequence:
-                if verbosity > 0:
-                    print 'Evolutions in %s baseline:' % app_label,', '.join(sequence)
-            for evo_label in sequence:
-                evolution = django_evolution.Evolution(app_label=app_label, 
-                                                       label=evo_label,
-                                                       version=latest_version)
-                evolution.save()
-
-    unapplied = get_unapplied_evolutions(app)
-    if unapplied:
-        print style.NOTICE('There are unapplied evolutions for %s.' % app.__name__.split('.')[-2])
-        
-    # Evolutions are checked over the entire project, so we only need to 
-    # check once. We do this check when Django Evolutions itself is synchronized.
-    if app == django_evolution:        
-        old_proj_sig = pickle.loads(str(latest_version.signature))
-        
-        # If any models have been added, a baseline must be set 
-        # for those new models
-        changed = False
-        for app_name, new_app_sig in proj_sig.items():
-            if app_name == '__version__':
-                # Ignore the __version__ tag
-                continue
-            old_app_sig = old_proj_sig.get(app_name, None)
-            if old_app_sig is None:
-                # App has been added
-                old_proj_sig[app_name] = proj_sig[app_name]
-                changed = True
-                continue
-            for model_name, new_model_sig in new_app_sig.items():
-                old_model_sig = old_app_sig.get(model_name, None)
-                if old_model_sig is None:
-                    # Model has been added
-                    old_proj_sig[app_name][model_name] = proj_sig[app_name][model_name]
-                    changed = True
-        
-        if changed:
-            if verbosity > 0:
-                print "Adding baseline version for new models"
-            latest_version = django_evolution.Version(signature=pickle.dumps(old_proj_sig))
-            latest_version.save()
-
-        # TODO: Model introspection step goes here. 
-        # # If the current database state doesn't match the last 
-        # # saved signature (as reported by latest_version),
-        # # then we need to update the Evolution table.
-        # actual_sig = introspect_project_sig()
-        # acutal = pickle.dumps(actual_sig)
-        # if actual != latest_version.signature:
-        #     nudge = Version(signature=actual)
-        #     nudge.save()
-        #     latest_version = nudge
-        
-        diff = Diff(old_proj_sig, proj_sig)
-        if not diff.is_empty():
-            print style.NOTICE('Project signature has changed - an evolution is required')
-            if verbosity > 1:
-                old_proj_sig = pickle.loads(str(latest_version.signature))
-                print diff
-                
-signals.post_syncdb.connect(evolution)

File django_evolution/management/commands/__init__.py

  • Ignore whitespace
Empty file removed.

File django_evolution/management/commands/evolve.py

  • Ignore whitespace
-from optparse import make_option
-import sys
-import copy
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle as pickle
-
-from django.conf import settings
-from django.core.exceptions import ImproperlyConfigured
-from django.core.management.base import BaseCommand, CommandError
-from django.db.models import get_apps, get_app, signals
-from django.db import connection, transaction
-
-from django_evolution import CannotSimulate, SimulationFailure, EvolutionException
-from django_evolution.diff import Diff
-from django_evolution.evolve import get_unapplied_evolutions, get_mutations
-from django_evolution.models import Version, Evolution
-from django_evolution.mutations import DeleteApplication
-from django_evolution.signature import create_project_sig
-from django_evolution.utils import write_sql, execute_sql
-
-class Command(BaseCommand):
-    option_list = BaseCommand.option_list + (
-        make_option('--noinput', action='store_false', dest='interactive', default=True,
-            help='Tells Django to NOT prompt the user for input of any kind.'),
-        make_option('--hint', action='store_true', dest='hint', default=False,
-            help='Generate an evolution script that would update the app.'),
-        make_option('--purge', action='store_true', dest='purge', default=False,
-            help='Generate evolutions to delete stale applications.'),
-        make_option('--sql', action='store_true', dest='compile_sql', default=False,
-            help='Compile a Django evolution script into SQL.'),
-        make_option('-x','--execute', action='store_true', dest='execute', default=False,
-            help='Apply the evolution to the database.'),
-    )
-    if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]:
-        option_list += make_option('-v','--verbosity', action='store', dest='verbosity', default='1',
-            type='choice', choices=['0', '1', '2'],
-            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
-
-    help = 'Evolve the models in a Django project.'
-    args = '<appname appname ...>'
-
-    requires_model_validation = False
-
-    def handle(self, *app_labels, **options):
-        verbosity = int(options['verbosity'])
-        interactive = options['interactive']
-        execute = options['execute']
-        compile_sql = options['compile_sql']
-        hint = options['hint']
-        purge = options['purge']
-
-        # Use the list of all apps, unless app labels are specified.
-        if app_labels:
-            if execute:
-                raise CommandError('Cannot specify an application name when executing evolutions.')
-            try:
-                app_list = [get_app(app_label) for app_label in app_labels]
-            except (ImproperlyConfigured, ImportError), e:
-                raise CommandError("%s. Are you sure your INSTALLED_APPS setting is correct?" % e)
-        else:
-            app_list = get_apps()
-
-        # Iterate over all applications running the mutations
-        evolution_required = False
-        simulated = True
-        sql = []
-        new_evolutions = []
-
-        current_proj_sig = create_project_sig()
-        current_signature = pickle.dumps(current_proj_sig)
-
-        try:
-            latest_version = Version.objects.latest('when')
-            database_sig = pickle.loads(str(latest_version.signature))
-            diff = Diff(database_sig, current_proj_sig)
-        except Evolution.DoesNotExist:
-            print self.style.ERROR("Can't evolve yet. Need to set an evolution baseline.")
-            sys.exit(1)
-
-        try:
-            for app in app_list:
-                app_label = app.__name__.split('.')[-2]
-                if hint:
-                    evolutions = []
-                    hinted_evolution = diff.evolution()
-                    mutations = hinted_evolution.get(app_label,[])
-                else:
-                    evolutions = get_unapplied_evolutions(app)
-                    mutations = get_mutations(app, evolutions)
-
-                if mutations:
-                    app_sql = ['-- Evolve application %s' % app_label]
-                    evolution_required = True
-                    for mutation in mutations:
-                        # Only compile SQL if we want to show it
-                        if compile_sql or execute:
-                            app_sql.extend(mutation.mutate(app_label, database_sig))
-
-                        # Now run the simulation, which will modify the signatures
-                        try:
-                            mutation.simulate(app_label, database_sig)
-                        except CannotSimulate:
-                            simulated = False
-                    new_evolutions.extend(Evolution(app_label=app_label, label=label)
-                                            for label in evolutions)
-
-                    if not execute:
-                        if compile_sql:
-                            write_sql(app_sql)
-                        else:
-                            print '#----- Evolution for %s' % app_label
-                            print 'from django_evolution.mutations import *'
-                            print 'from django.db import models'
-                            print
-                            print 'MUTATIONS = ['
-                            print '   ',
-                            print ',\n    '.join(unicode(m) for m in mutations)
-                            print ']'
-                            print '#----------------------'
-
-                    sql.extend(app_sql)
-                else:
-                    if verbosity > 1:
-                        print 'Application %s is up to date' % app_label
-
-            # Process the purged applications if requested to do so.
-            if purge:
-                if diff.deleted:
-                    evolution_required = True
-                    delete_app = DeleteApplication()
-                    purge_sql = []
-                    for app_label in diff.deleted:
-                        if compile_sql or execute:
-                            purge_sql.append('-- Purge application %s' % app_label)
-                            purge_sql.extend(delete_app.mutate(app_label, database_sig))
-                        delete_app.simulate(app_label, database_sig)
-
-                    if not execute:
-                        if compile_sql:
-                            write_sql(purge_sql)
-                        else:
-                            print 'The following application(s) can be purged:'
-                            for app_label in diff.deleted:
-                                print '    ', app_label
-                            print
-                    sql.extend(purge_sql)
-                else:
-                    if verbosity > 1:
-                        print 'No applications need to be purged.'
-
-        except EvolutionException, e:
-            print self.style.ERROR(e)
-            sys.exit(1)
-
-        if simulated:
-            diff = Diff(database_sig, current_proj_sig)
-            if not diff.is_empty(not purge):
-                if hint:
-                    print self.style.ERROR('Your models contain changes that Django Evolution cannot resolve automatically.')
-                    print 'This is probably due to a currently unimplemented mutation type.'
-                    print 'You will need to manually construct a mutation to resolve the remaining changes.'
-                else:
-                    print self.style.ERROR('The stored evolutions do not completely resolve all model changes.')
-                    print 'Run `./manage.py evolve --hint` to see a suggestion for the changes required.'
-                print
-                print 'The following are the changes that could not be resolved:'
-                print diff
-                sys.exit(1)
-        else:
-            print self.style.NOTICE('Evolution could not be simulated, possibly due to raw SQL mutations')
-
-        if evolution_required:
-            if execute:
-                # Now that we've worked out the mutations required,
-                # and we know they simulate OK, run the evolutions
-                if interactive:
-                    confirm = raw_input("""
-You have requested a database evolution. This will alter tables
-and data currently in the %r database, and may result in
-IRREVERSABLE DATA LOSS. Evolutions should be *thoroughly* reviewed
-prior to execution.
-
-Are you sure you want to execute the evolutions?
-
-Type 'yes' to continue, or 'no' to cancel: """ % settings.DATABASE_NAME)
-                else:
-                    confirm = 'yes'
-
-                if confirm.lower() == 'yes':
-                    # Begin Transaction
-                    transaction.enter_transaction_management()
-                    transaction.managed(True)
-                    cursor = connection.cursor()
-                    try:
-                        # Perform the SQL
-                        execute_sql(cursor, sql)
-
-                        # Now update the evolution table
-                        version = Version(signature=current_signature)
-                        version.save()
-                        for evolution in new_evolutions:
-                            evolution.version = version
-                            evolution.save()
-
-                        transaction.commit()
-                    except Exception, ex:
-                        transaction.rollback()
-                        print self.style.ERROR('Error applying evolution: %s' % str(ex))
-                        sys.exit(1)
-                    transaction.leave_transaction_management()
-
-                    if verbosity > 0:
-                        print 'Evolution successful.'
-                else:
-                    print self.style.ERROR('Evolution cancelled.')
-            elif not compile_sql:
-                if verbosity > 0:
-                    if simulated:
-                        print "Trial evolution successful."
-                        print "Run './manage.py evolve %s--execute' to apply evolution." % (hint and '--hint ' or '')
-        else:
-            if verbosity > 0:
-                print 'No evolution required.'

File django_evolution/models.py

  • Ignore whitespace
-from datetime import datetime
-
-from django.db import models
-
-class Version(models.Model):
-    signature = models.TextField()
-    when = models.DateTimeField(default=datetime.now)
-
-    class Meta:
-        ordering = ('-when',)
-        db_table = 'django_project_version'
-
-    def __unicode__(self):
-        if not self.evolutions.count():
-            return u'Hinted version, updated on %s' % self.when
-        return u'Stored version, updated on %s' % self.when
-
-class Evolution(models.Model):
-    version = models.ForeignKey(Version, related_name='evolutions')
-    app_label = models.CharField(max_length=200)
-    label = models.CharField(max_length=100)
-
-    class Meta:
-        db_table = 'django_evolution'
-        
-    def __unicode__(self):
-        return u"Evolution %s, applied to %s" % (self.label, self.app_label)

File django_evolution/mutations.py

  • Ignore whitespace
-import copy
-
-from django.contrib.contenttypes import generic
-from django.db.models.fields import *
-from django.db.models.fields.related import *
-from django.db import models
-from django.utils.functional import curry
-
-from django_evolution.signature import ATTRIBUTE_DEFAULTS, create_field_sig
-from django_evolution import CannotSimulate, SimulationFailure, EvolutionNotImplementedError
-from django_evolution.db import evolver
-
-FK_INTEGER_TYPES = ['AutoField', 'PositiveIntegerField', 'PositiveSmallIntegerField']
-
-def create_field(proj_sig, field_name, field_type, field_attrs):
-    """
-    Create an instance of a field from a field signature. This is useful for
-    accessing all the database property mechanisms built into fields.
-    """
-    # related_model isn't a valid field attribute, so it must be removed
-    # prior to instantiating the field, but it must be restored
-    # to keep the signature consistent.
-    related_model = field_attrs.pop('related_model', None)
-    if related_model:
-        related_app_name, related_model_name = related_model.split('.')
-        related_model_sig = proj_sig[related_app_name][related_model_name]
-        to = MockModel(proj_sig, related_app_name, related_model_name, related_model_sig, stub=True)
-        field = field_type(to, name=field_name, **field_attrs)
-        field_attrs['related_model'] = related_model
-    else:
-        field = field_type(name=field_name, **field_attrs)
-    field.set_attributes_from_name(field_name)
-
-    return field
-
-class MockMeta(object):
-    """
-    A mockup of a models Options object, based on the model signature.
-
-    The stub argument is used to circumvent recursive relationships. If
-    'stub' is provided, the constructed model will only be a stub -
-    it will only have a primary key field.
-    """
-    def __init__(self, proj_sig, app_name, model_name, model_sig, stub=False):
-        self.object_name = model_name
-        self.app_label = app_name
-        self.meta = {
-            'order_with_respect_to': None,
-            'has_auto_field': None
-        }
-        self.meta.update(model_sig['meta'])
-        self._fields = {}
-        self._many_to_many = {}
-        self.abstract = False
-
-        for field_name,field_sig in model_sig['fields'].items():
-            if not stub or field_sig.get('primary_key', False):
-                field_type = field_sig.pop('field_type')
-                field = create_field(proj_sig, field_name, field_type, field_sig)
-
-                if AutoField == type(field):
-                    self.meta['has_auto_field'] = True
-                    self.meta['auto_field'] = field
-
-                field_sig['field_type'] = field_type
-
-                if ManyToManyField == type(field):
-                    self._many_to_many[field.name] = field
-                else:
-                    self._fields[field.name] = field
-
-                field.set_attributes_from_name(field_name)
-                if field_sig.get('primary_key', False):
-                    self.pk = field
-
-    def __getattr__(self, name):
-        return self.meta[name]
-
-    def get_field(self, name):
-        try:
-            return self._fields[name]
-        except KeyError:
-            try:
-                return self._many_to_many[name]
-            except KeyError:
-                raise FieldDoesNotExist('%s has no field named %r' % (self.object_name, name))
-
-    def get_field_by_name(self, name):
-        return (self.get_field(name), None, True, None)
-
-    def get_fields(self):
-        return self._fields.values()
-
-    def get_many_to_many_fields(self):
-        return self._many_to_many.values()
-
-    local_fields = property(fget=get_fields)
-    local_many_to_many = property(fget=get_many_to_many_fields)
-
-class MockModel(object):
-    """
-    A mockup of a model object, providing sufficient detail
-    to derive database column and table names using the standard
-    Django fields.
-    """
-    def __init__(self, proj_sig, app_name, model_name, model_sig, stub=False):
-        self.app_name = app_name
-        self.model_name = model_name
-        self._meta = MockMeta(proj_sig, app_name, model_name, model_sig, stub)
-
-    def __eq__(self, other):
-        return self.app_name == other.app_name and self.model_name == other.model_name
-
-class MockRelated(object):
-    """
-    A mockup of django.db.models.related.RelatedObject, providing
-    sufficient detail to derive database column and table names using
-    the standard Django fields.
-    """
-    def __init__(self, related_model, model, field):
-        self.parent_model = related_model
-        self.model = model
-        self.field = field
-
-class BaseMutation:
-    def __init__(self):
-        pass
-
-    def mutate(self, app_label, proj_sig):
-        """
-        Performs the mutation on the database. Database changes will occur
-        after this function is invoked.
-        """
-        raise NotImplementedError()
-
-    def simulate(self, app_label, proj_sig):
-        """
-        Performs a simulation of the mutation to be performed. The purpose of
-        the simulate function is to ensure that after all mutations have occured
-        the database will emerge in a state consistent with the currently loaded
-        models file.
-        """
-        raise NotImplementedError()
-
-class SQLMutation(BaseMutation):
-    def __init__(self, tag, sql, update_func=None):
-        self.tag = tag
-        self.sql = sql
-        self.update_func = update_func
-
-    def __str__(self):
-        return "SQLMutation('%s')" % self.tag
-
-    def simulate(self, app_label, proj_sig):
-        "SQL mutations cannot be simulated unless an update function is provided"
-        if callable(self.update_func):
-            self.update_func(app_label, proj_sig)
-        else:
-            raise CannotSimulate('Cannot simulate SQLMutations')
-
-    def mutate(self, app_label, proj_sig):
-        "The mutation of an SQL mutation returns the raw SQL"
-        return self.sql
-
-class DeleteField(BaseMutation):
-    def __init__(self, model_name, field_name):
-
-        self.model_name = model_name
-        self.field_name = field_name
-
-    def __str__(self):
-        return "DeleteField('%s', '%s')" % (self.model_name, self.field_name)
-
-    def simulate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-
-        # If the field was used in the unique_together attribute, update it.
-        unique_together = model_sig['meta']['unique_together']
-        unique_together_list = []
-        for ut_index in range(0, len(unique_together), 1):
-            ut = unique_together[ut_index]
-            unique_together_fields = []
-            for field_name_index in range(0, len(ut), 1):
-                field_name = ut[field_name_index]
-                if not field_name == self.field_name:
-                    unique_together_fields.append(field_name)
-
-            unique_together_list.append(tuple(unique_together_fields))
-        model_sig['meta']['unique_together'] = tuple(unique_together_list)
-
-        if model_sig['fields'][self.field_name].get('primary_key',False):
-            raise SimulationFailure('Cannot delete a primary key.')
-
-        # Simulate the deletion of the field.
-        try:
-            field_sig = model_sig['fields'].pop(self.field_name)
-        except KeyError, ke:
-            raise SimulationFailure('Cannot find the field named "%s".' % self.field_name)
-
-    def mutate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-        field_sig = model_sig['fields'][self.field_name]
-
-        model = MockModel(proj_sig, app_label, self.model_name, model_sig)
-        # Temporarily remove field_type from the field signature
-        # so that we can create a field
-        field_type = field_sig.pop('field_type')
-        field = create_field(proj_sig, self.field_name, field_type, field_sig)
-        field_sig['field_type'] = field_type
-
-        if field_type == models.ManyToManyField:
-            sql_statements = evolver.delete_table(field._get_m2m_db_table(model._meta))
-        else:
-            sql_statements = evolver.delete_column(model, field)
-
-        return sql_statements
-
-class AddField(BaseMutation):
-    def __init__(self, model_name, field_name, field_type, initial=None, **kwargs):
-        self.model_name = model_name
-        self.field_name = field_name
-        self.field_type = field_type
-        self.field_attrs = kwargs
-        self.initial = initial
-
-    def __str__(self):
-        params = (self.model_name, self.field_name, self.field_type.__name__)
-        str_output = ["'%s', '%s', models.%s" % params]
-
-        if self.initial is not None:
-            str_output.append('initial=%s' % repr(self.initial))
-
-        for key,value in self.field_attrs.items():
-            str_output.append("%s=%s" % (key,repr(value)))
-        return 'AddField(' + ', '.join(str_output) + ')'
-
-    def simulate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-
-        if self.field_name in model_sig['fields']:
-            raise SimulationFailure("Model '%s.%s' already has a field named '%s'" % (
-                        app_label, self.model_name, self.field_name))
-
-        if self.field_type != models.ManyToManyField and not self.field_attrs.get('null', ATTRIBUTE_DEFAULTS['null']):
-            if self.initial is None:
-                raise SimulationFailure("Cannot create new column '%s' on '%s.%s' without a non-null initial value." % (
-                        self.field_name, app_label, self.model_name))
-
-        model_sig['fields'][self.field_name] = {
-            'field_type': self.field_type,
-        }
-        model_sig['fields'][self.field_name].update(self.field_attrs)
-
-    def mutate(self, app_label, proj_sig):
-        if self.field_type == models.ManyToManyField:
-            return self.add_m2m_table(app_label, proj_sig)
-        else:
-            return self.add_column(app_label, proj_sig)
-
-    def add_column(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-
-        model = MockModel(proj_sig, app_label, self.model_name, model_sig)
-        field = create_field(proj_sig, self.field_name, self.field_type, self.field_attrs)
-
-        sql_statements = evolver.add_column(model, field, self.initial)
-
-        # Create SQL index if necessary
-        sql_statements.extend(evolver.create_index(model, field))
-
-        return sql_statements
-
-    def add_m2m_table(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-
-        model = MockModel(proj_sig, app_label, self.model_name, model_sig)
-        field = create_field(proj_sig, self.field_name, self.field_type, self.field_attrs)
-        field.m2m_db_table = curry(field._get_m2m_db_table, model._meta)
-
-        related_app_label, related_model_name = self.field_attrs['related_model'].split('.')
-        related_sig = proj_sig[related_app_label][related_model_name]
-        related_model = MockModel(proj_sig, related_app_label, related_model_name, related_sig)
-        related = MockRelated(related_model, model, field)
-
-        field.m2m_column_name = curry(field._get_m2m_column_name, related)
-        field.m2m_reverse_name = curry(field._get_m2m_reverse_name, related)
-
-        sql_statements = evolver.add_m2m_table(model, field)
-
-        return sql_statements
-
-class RenameField(BaseMutation):
-    def __init__(self, model_name, old_field_name, new_field_name,
-                 db_column=None, db_table=None):
-        self.model_name = model_name
-        self.old_field_name = old_field_name
-        self.new_field_name = new_field_name
-        self.db_column = db_column
-        self.db_table = db_table
-
-    def __str__(self):
-        params = "'%s', '%s', '%s'" % (self.model_name, self.old_field_name, self.new_field_name)
-
-        if self.db_column:
-            params = params + ", db_column='%s'" % (self.db_column)
-        if self.db_table:
-            params = params + ", db_table='%s'" % (self.db_table)
-
-        return "RenameField(%s)" % params
-
-    def simulate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-        field_dict = model_sig['fields']
-        field_sig = field_dict[self.old_field_name]
-
-        if models.ManyToManyField == field_sig['field_type']:
-            if self.db_table:
-                field_sig['db_table'] = self.db_table
-            else:
-                field_sig.pop('db_table',None)
-        elif self.db_column:
-            field_sig['db_column'] = self.db_column
-        else:
-            # db_column and db_table were not specified (or not specified for the
-            # appropriate field types). Clear the old value if one was set. This
-            # amounts to resetting the column or table name to the Django default name
-            field_sig.pop('db_column',None)
-
-        field_dict[self.new_field_name] = field_dict.pop(self.old_field_name)
-
-    def mutate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-        old_field_sig = model_sig['fields'][self.old_field_name]
-
-        # Temporarily remove the field type so that we can create mock field instances
-        field_type = old_field_sig.pop('field_type')
-        # Duplicate the old field sig, and apply the table/column changes
-        new_field_sig = copy.copy(old_field_sig)
-        if models.ManyToManyField == field_type:
-            if self.db_table:
-                new_field_sig['db_table'] = self.db_table
-            else:
-                new_field_sig.pop('db_table', None)
-        elif self.db_column:
-            new_field_sig['db_column'] = self.db_column
-        else:
-            new_field_sig.pop('db_column', None)
-
-        # Create the mock field instances.
-        old_field = create_field(proj_sig, self.old_field_name, field_type, old_field_sig)
-        new_field = create_field(proj_sig, self.new_field_name, field_type, new_field_sig)
-
-        # Restore the field type to the signature
-        old_field_sig['field_type'] = field_type
-
-        opts = MockMeta(proj_sig, app_label, self.model_name, model_sig)
-        if models.ManyToManyField == field_type:
-            old_m2m_table = old_field._get_m2m_db_table(opts)
-            new_m2m_table = new_field._get_m2m_db_table(opts)
-
-            return evolver.rename_table(old_m2m_table, new_m2m_table)
-        else:
-            return evolver.rename_column(opts, old_field, new_field)
-
-class ChangeField(BaseMutation):
-    def __init__(self, model_name, field_name, initial=None, **kwargs):
-        self.model_name = model_name
-        self.field_name = field_name
-        self.field_attrs = kwargs
-        self.initial = initial
-
-    def __str__(self):
-        params = (self.model_name, self.field_name)
-        str_output = ["'%s', '%s'" % params]
-
-        str_output.append('initial=%s' % repr(self.initial))
-
-        for attr_name, attr_value in self.field_attrs.items():
-            if str == type(attr_value):
-                str_attr_value = "'%s'" % attr_value
-            else:
-                str_attr_value = str(attr_value)
-            str_output.append('%s=%s' % (attr_name, str_attr_value,))
-
-        return 'ChangeField(' + ', '.join(str_output) + ')'
-        
-        
-    def simulate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-        field_sig = model_sig['fields'][self.field_name]
-
-        # Catch for no-op changes.
-        for field_attr, attr_value in self.field_attrs.items():
-            field_sig[field_attr] = attr_value
-
-        if self.field_attrs.has_key('null'):
-            if field_sig['field_type'] != models.ManyToManyField and not self.field_attrs['null']:
-                if self.initial is None:
-                    raise SimulationFailure("Cannot change column '%s' on '%s.%s' without a non-null initial value." % (
-                            self.field_name, app_label, self.model_name))
-
-    def mutate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-        old_field_sig = model_sig['fields'][self.field_name]
-        model = MockModel(proj_sig, app_label, self.model_name, model_sig)
-
-        sql_statements = []
-        for field_attr, attr_value in self.field_attrs.items():
-            old_field_attr = old_field_sig.get(field_attr, ATTRIBUTE_DEFAULTS[field_attr])
-            # Avoid useless SQL commands if nothing has changed.
-            if not old_field_attr == attr_value:
-                try:
-                    evolver_func = getattr(evolver, 'change_%s' % field_attr)
-                    if field_attr == 'null':
-                        sql_statements.extend(evolver_func(model, self.field_name, attr_value, self.initial))
-                    elif field_attr == 'db_table':
-                        sql_statements.extend(evolver_func(old_field_attr, attr_value))
-                    else:
-                        sql_statements.extend(evolver_func(model, self.field_name, attr_value))
-                except AttributeError, ae:
-                    raise EvolutionNotImplementedError("ChangeField does not support modifying the '%s' attribute on '%s.%s'." % (field_attr, self.model_name, self.field_name))
-
-        return sql_statements
-
-class DeleteModel(BaseMutation):
-    def __init__(self, model_name):
-        self.model_name = model_name
-
-    def __str__(self):
-        return "DeleteModel(%r)" % self.model_name
-
-    def simulate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        # Simulate the deletion of the model.
-        del app_sig[self.model_name]
-
-    def mutate(self, app_label, proj_sig):
-        app_sig = proj_sig[app_label]
-        model_sig = app_sig[self.model_name]
-
-        sql_statements = []
-        model = MockModel(proj_sig, app_label, self.model_name, model_sig)
-        # Remove any many to many tables.
-        for field_name, field_sig in model_sig['fields'].items():
-            if field_sig['field_type'] == models.ManyToManyField:
-                field = model._meta.get_field(field_name)
-                m2m_table = field._get_m2m_db_table(model._meta)
-                sql_statements += evolver.delete_table(m2m_table)
-        # Remove the table itself.
-        sql_statements += evolver.delete_table(model._meta.db_table)
-
-        return sql_statements
-
-class DeleteApplication(BaseMutation):
-    def __str__(self):
-        return 'DeleteApplication()'
-
-    def simulate(self, app_label, proj_sig):
-        del proj_sig[app_label]
-
-    def mutate(self, app_label, proj_sig):
-        sql_statements = []
-        app_sig = proj_sig[app_label]
-        for model_name in app_sig.keys():
-            sql_statements.extend(DeleteModel(model_name).mutate(app_label, proj_sig))
-        return sql_statements

File django_evolution/signature.py

  • Ignore whitespace
-from django.db.models import get_apps, get_models
-from django.db.models.fields.related import *
-from django.conf import global_settings
-from django.contrib.contenttypes import generic
-
-ATTRIBUTE_DEFAULTS = {
-    # Common to all fields
-    'primary_key': False,
-    'max_length' : None,
-    'unique' : False,
-    'null' : False,
-    'db_index' : False,
-    'db_column' : None,
-    'db_tablespace' : global_settings.DEFAULT_TABLESPACE,
-    'rel': None,
-    # Decimal Field
-    'max_digits' : None,
-    'decimal_places' : None,
-    # ManyToManyField
-    'db_table': None
-}
-
-# r7790 modified the unique attribute of the meta model to be
-# a property that combined an underlying _unique attribute with
-# the primary key attribute. We need the underlying property, 
-# but we don't want to affect old signatures (plus the
-# underscore is ugly :-).
-ATTRIBUTE_ALIASES = {
-    'unique': '_unique'
-}
-
-def create_field_sig(field):
-    field_sig = {
-        'field_type': field.__class__,
-    }
-        
-    for attrib in ATTRIBUTE_DEFAULTS.keys():
-        alias = ATTRIBUTE_ALIASES.get(attrib, attrib)
-        if hasattr(field,alias):
-            value = getattr(field,alias)
-            if isinstance(field, ForeignKey):
-                if attrib == 'db_index':
-                    default = True
-                else:
-                    default = ATTRIBUTE_DEFAULTS[attrib]
-            else:
-                default = ATTRIBUTE_DEFAULTS[attrib]
-            # only store non-default values
-            if default != value:
-                field_sig[attrib] = value
-                
-    rel = field_sig.pop('rel', None)
-    if rel:
-        field_sig['related_model'] = '.'.join([rel.to._meta.app_label, rel.to._meta.object_name])
-    return field_sig
-    
-def create_model_sig(model):
-    model_sig = {
-        'meta': {
-            'unique_together': model._meta.unique_together,
-            'db_tablespace': model._meta.db_tablespace,
-            'db_table': model._meta.db_table,
-            'pk_column': model._meta.pk.column,
-        },
-        'fields': {},
-    }
-
-    for field in model._meta.local_fields + model._meta.local_many_to_many:
-        # Special case - don't generate a signature for generic relations
-        if not isinstance(field, generic.GenericRelation):
-            model_sig['fields'][field.name] = create_field_sig(field)
-    return model_sig
-    
-def create_app_sig(app):
-    """
-    Creates a dictionary representation of the models in a given app.
-    Only those attributes that are interesting from a schema-evolution
-    perspective are included.
-    """
-    app_sig = {}
-    for model in get_models(app):
-        app_sig[model._meta.object_name] = create_model_sig(model)
-    return app_sig    
-
-def create_project_sig():
-    """
-    Create a dictionary representation of the apps in a given project.
-    """
-    proj_sig = {
-        '__version__': 1,
-    }
-    for app in get_apps():
-        proj_sig[app.__name__.split('.')[-2]] = create_app_sig(app)
-    return proj_sig

File django_evolution/utils.py

  • Ignore whitespace
-from django_evolution.db import evolver
-
-def write_sql(sql):
-    "Output a list of SQL statements, unrolling parameters as required"
-    for statement in sql:
-        if isinstance(statement, tuple):
-            print unicode(statement[0] % tuple(evolver.quote_sql_param(s) for s in statement[1]))
-        else:
-            print unicode(statement)
-
-def execute_sql(cursor, sql):
-    """
-    Execute a list of SQL statements on the provided cursor, unrolling 
-    parameters as required
-    """
-    for statement in sql:
-        if isinstance(statement, tuple):
-            if not statement[0].startswith('--'):
-                cursor.execute(*statement)
-        else:
-            if not statement.startswith('--'):
-                cursor.execute(statement)