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)
def get_mutations(app, evolution_labels, database): """ 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]) if app_name in BUILTIN_SEQUENCES: module_name = 'django_evolution.builtin_evolutions' else: module_name = '%s.evolutions' % app_name evolution_module = __import__(module_name, {}, {}, ['']) except ImportError: return [] mutations = [] for label in evolution_labels: directory_name = os.path.dirname(evolution_module.__file__) # The first element is used for compatibility purposes. filenames = [ os.path.join(directory_name, label + '.sql'), os.path.join(directory_name, "%s_%s.sql" % (database, label)), ] found = False for filename in filenames: if os.path.exists(filename): sql = [] sql_file = open(sql_file_name) for line in sql_file: sql.append(line) mutations.append(SQLMutation(label, sql)) found = True break if not found: try: module_name = [evolution_module.__name__, label] module = __import__('.'.join(module_name), {}, {}, [module_name]); mutations.extend(module.MUTATIONS) except ImportError: raise EvolutionException( 'Error: Failed to find an SQL or Python evolution named %s' % label) return mutations
def get_mutations(app, evolution_labels, database): """ 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]) if app_name in BUILTIN_SEQUENCES: module_name = 'django_evolution.builtin_evolutions' else: module_name = '%s.evolutions' % app_name evolution_module = __import__(module_name, {}, {}, ['']) except ImportError: return [] mutations = [] for label in evolution_labels: directory_name = os.path.dirname(evolution_module.__file__) # The first element is used for compatibility purposes. filenames = [ os.path.join(directory_name, label + '.sql'), os.path.join(directory_name, "%s_%s.sql" % (database, label)), ] found = False for filename in filenames: if os.path.exists(filename): sql = [] sql_file = open(sql_file_name) for line in sql_file: sql.append(line) mutations.append(SQLMutation(label, sql)) found = True break if not found: try: module_name = [evolution_module.__name__, label] module = __import__('.'.join(module_name), {}, {}, [module_name]) mutations.extend(module.MUTATIONS) except ImportError: raise EvolutionException( 'Error: Failed to find an SQL or Python evolution named %s' % label) if is_multi_db(): latest_version = Version.objects.using(database).latest('when') else: latest_version = Version.objects.latest('when') app_label = app.__name__.split('.')[-2] old_proj_sig = pickle.loads(str(latest_version.signature)) proj_sig = create_project_sig(database) if app_label in old_proj_sig and app_label in proj_sig: # We want to go through now and make sure we're only applying # evolutions for models where the signature is different between # what's stored and what's current. # # The reason for this is that we may have just installed a baseline, # which would have the up-to-date signature, and we might be trying # to apply evolutions on top of that (which would already be applied). # These would generate errors. So, try hard to prevent that. old_app_sig = old_proj_sig[app_label] app_sig = proj_sig[app_label] changed_models = set() # Find the list of models in the latest signature of this app # that aren't in the old signature. for model_name, model_sig in app_sig.iteritems(): if (model_name not in old_app_sig or old_app_sig[model_name] != model_sig): changed_models.add(model_name) # Now do the same for models in the old signature, in case the # model has been deleted. for model_name, model_sig in old_app_sig.iteritems(): if model_name not in app_sig: changed_models.add(model_name) # We should now have a full list of which models changed. Filter # the list of mutations appropriately. mutations = [ mutation for mutation in mutations if (not hasattr(mutation, 'model_name') or mutation.model_name in changed_models) ] return mutations
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 old_fields = old_model_sig['fields'] new_fields = new_model_sig['fields'] # Look for deleted or modified fields for field_name, old_field_data in old_fields.items(): new_field_data = new_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 new_fields = new_model_sig['fields'] for field_name, new_field_data in new_fields.items(): old_field_data = old_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 __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))