def _save_project_sig(self, new_evolutions): """Save the project signature and any new evolutions. This will serialize the current modified project signature to the database and write any new evolutions, attaching them to the current project version. This can be called many times for one evolver instance. After the first time, the version already saved will simply be updated. Args: new_evolutions (list of django_evolution.models.Evolution): The list of new evolutions to save to the database. Raises: django_evolution.errors.EvolutionExecutionError: There was an error saving to the database. """ version = self.version if version is None: version = Version(signature=self.project_sig) self.version = version try: version.save(using=self.database_name) if new_evolutions: for evolution in new_evolutions: evolution.version = version Evolution.objects.using( self.database_name).bulk_create(new_evolutions) except Exception as e: raise EvolutionExecutionError( _('Error saving new evolution version information: %s') % e, detailed_error=six.text_type(e))
if confirm.lower() == 'yes': # Begin Transaction transaction.enter_transaction_management(**using_args) transaction.managed(flag=True, **using_args) if is_multi_db(): cursor = connections[database].cursor() else: cursor = connection.cursor() try: # Perform the SQL execute_sql(cursor, sql) # Now update the evolution table version = Version(signature=current_signature) version.save(**using_args) for evolution in new_evolutions: evolution.version = version evolution.save(**using_args) transaction.commit(**using_args) except Exception, ex: transaction.rollback(**using_args) raise CommandError('Error applying evolution: %s' % str(ex)) transaction.leave_transaction_management(**using_args) if verbosity > 0:
def _on_app_models_updated(app, verbosity=1, using=DEFAULT_DB_ALIAS, **kwargs): """Handler for when an app's models were updated. This is called in response to a syncdb or migrate operation for an app. It will install baselines for any new models, record the changes in the evolution history, and notify the user if any of the changes require an evolution. Args: app (module): The app models module that was updated. verbosity (int, optional): The verbosity used to control output. This will have been provided by the syncdb or migrate command. using (str, optional): The database being updated. **kwargs (dict): Additional keyword arguments provided by the signal handler for the syncdb or migrate operation. """ project_sig = ProjectSignature.from_database(using) try: latest_version = Version.objects.current_version(using=using) except Version.DoesNotExist: # We need to create a baseline version. if verbosity > 0: print("Installing baseline version") latest_version = Version(signature=project_sig) latest_version.save(using=using) for a in get_apps(): _install_baseline(app=a, latest_version=latest_version, using=using, verbosity=verbosity) unapplied = get_unapplied_evolutions(app, using) if unapplied: print( style.NOTICE('There are unapplied evolutions for %s.' % get_app_label(app))) # 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 is get_app('django_evolution'): old_project_sig = latest_version.signature # If any models or apps have been added, a baseline must be set # for those new models changed = False new_apps = [] for new_app_sig in project_sig.app_sigs: app_id = new_app_sig.app_id old_app_sig = old_project_sig.get_app_sig(app_id) if old_app_sig is None: # App has been added old_project_sig.add_app_sig(new_app_sig.clone()) new_apps.append(app_id) changed = True else: for new_model_sig in new_app_sig.model_sigs: model_name = new_model_sig.model_name old_model_sig = old_app_sig.get_model_sig(model_name) if old_model_sig is None: # Model has been added old_app_sig.add_model_sig( project_sig.get_app_sig(app_id).get_model_sig( model_name).clone()) changed = True if changed: if verbosity > 0: print("Adding baseline version for new models") latest_version = Version(signature=old_project_sig) latest_version.save(using=using) for app_name in new_apps: app = get_app(app_name, True) if app: _install_baseline(app=app, latest_version=latest_version, using=using, verbosity=verbosity) # 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_project_sig, project_sig) if not diff.is_empty(): print( style.NOTICE( 'Project signature has changed - an evolution is required') ) if verbosity > 1: print(diff)