Esempio n. 1
0
def db_get_installable_models_for_app(app, db_state):
    """Return models that can be installed in a database.

    Args:
        app (module):
            The models module for the app.

        db_state (django_evolution.db.state.DatabaseState):
            The introspected state of the database.
    """
    app_label = get_app_label(app)

    # On Django >= 1.7, models for a M2M field will be created automatically,
    # so we don't want to include them in any results.
    #
    # On Django < 1.7, we need to explicitly return these models.
    include_auto_created = apps is None

    return [
        model
        for model in get_models(app, include_auto_created=include_auto_created)
        if (not db_state.has_model(model) and
            db_router_allows_schema_upgrade(db_state.db_name, app_label,
                                            model))
    ]
Esempio n. 2
0
def sql_create(app, db_name=None):
    """Return SQL statements for creating all models for an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements used to create the models for the app.
    """
    connection = connections[db_name or DEFAULT_DB_ALIAS]

    if BaseDatabaseSchemaEditor:
        # Django >= 1.7
        with connection.schema_editor(collect_sql=True) as schema_editor:
            for model in get_models(app):
                schema_editor.create_model(model)

        return schema_editor.collected_sql
    else:
        # Django < 1.7
        style = color.no_style()

        return (sql.sql_create(app, style, connection) +
                sql.sql_indexes(app, style, connection))
Esempio n. 3
0
def sql_create(app, db_name=None):
    """Return SQL statements for creating all models for an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements used to create the models for the app.
    """
    connection = connections[db_name or DEFAULT_DB_ALIAS]

    if BaseDatabaseSchemaEditor:
        # Django >= 1.7
        with connection.schema_editor(collect_sql=True) as schema_editor:
            for model in get_models(app):
                schema_editor.create_model(model)

        return schema_editor.collected_sql
    else:
        # Django < 1.7
        style = color.no_style()

        return (sql.sql_create(app, style, connection) +
                sql.sql_indexes(app, style, connection))
Esempio n. 4
0
def get_model_rel_tree():
    """Return the full field relationship tree for all registered models.

    This will walk through every field in every model registered in Django,
    storing the relationships between objects, caching them. Each entry in
    the resulting dictionary will be a table mapping to a list of relation
    fields that point back at it.

    This can be used to quickly locate any and all reverse relations made to
    a field.

    This is similar to Django's built-in reverse relation tree used internally
    (with different implementations) in
    :py:class:`django.db.models.options.Options`, but works across all
    supported versions of Django, and supports cache clearing.

    Version Added:
        2.2

    Returns:
        dict:
        The model relation tree.
    """
    global _rel_tree_cache

    if _rel_tree_cache is not None:
        return _rel_tree_cache

    rel_tree = defaultdict(list)
    all_models = get_models(include_auto_created=True)

    # We'll walk the entire model tree, looking for any immediate fields on
    # each model, building a mapping of models to fields that reference the
    # model.
    for cur_model in all_models:
        if cur_model._meta.abstract:
            continue

        for field in iter_model_fields(cur_model,
                                       include_parent_models=False,
                                       include_forward_fields=True,
                                       include_reverse_fields=False,
                                       include_hidden_fields=False):
            if (get_field_is_relation(field)
                    and get_remote_field_related_model(field) is not None):
                remote_field = get_remote_field(field)
                remote_field_model = get_remote_field_model(remote_field)

                # Make sure this isn't a "self" relation or similar.
                if not isinstance(remote_field_model, six.string_types):
                    db_table = \
                        remote_field_model._meta.concrete_model._meta.db_table
                    rel_tree[db_table].append(field)

    _rel_tree_cache = rel_tree

    return rel_tree
Esempio n. 5
0
    def handle(self, **options):
        """Handle the command.

        Args:
            **options (dict, unused):
                Options parsed on the command line. For this command, no
                options are available.
        """
        models = []

        for app in get_apps():
            models.extend(get_models(app))

        OBJECT_LIMIT = 150

        serializer = serializers.get_serializer('json')()

        totalobjs = 0

        for model in models:
            totalobjs += model.objects.count()

        prev_pct = -1
        i = 0

        self.stderr.write(_('Dump the database. This may take a while...\n'))

        self.stdout.write('# dbdump v1 - %s objects' % totalobjs)

        for model in models:
            count = model.objects.count()
            j = 0

            while j < count:
                for obj in model.objects.all()[j:j + OBJECT_LIMIT].iterator():
                    value = serializer.serialize([obj])

                    if value != '[]':
                        self.stdout.write(value[1:-1])  # Skip the "[" and "]"

                    i += 1
                    pct = i * 100 / totalobjs

                    if pct != prev_pct:
                        self.stderr.write('  [%s%%]\r' % pct)
                        self.stderr.flush()
                        prev_pct = pct

                j += OBJECT_LIMIT

        self.stderr.write('\nDone.\n')
Esempio n. 6
0
def replace_models(database_state, apps_to_models):
    """Temporarily replace existing models with new definitions.

    This allows a unit test to replace some previously-defined models, backing
    up the old ones and restoring them once the operations are complete.

    Args:
        database_state (django_evolution.db.state.DatabaseState):
            The currently-computed database state.

        apps_to_models (dict):
            A mapping of app labels to lists of tuples. Each tuple contains:

            1. The model class name to register (which can be different from
               the real class name).
            2. The model class.

    Context:
        The replaced models will be available in Django.
    """
    old_models_info = []

    for app_label, app_models in six.iteritems(apps_to_models):
        app = get_app(app_label)
        old_models_info.append((app_label, get_models(app)))

        # Needed in Django 1.6 to ensure the model isn't filtered out in
        # our own get_models() calls.
        for name, app_model in app_models:
            app_model.__module__ = app.__name__

    try:
        for app_label, app_models in six.iteritems(apps_to_models):
            register_models(database_state=database_state,
                            models=app_models,
                            new_app_label=app_label)

        yield
    finally:
        unregister_test_models()

        for app_label, old_models in old_models_info:
            register_app_models(
                app_label,
                [
                    (model._meta.object_name.lower(), model)
                    for model in old_models
                ],
                reset=True)
Esempio n. 7
0
def sql_delete(app, db_name=None):
    """Return SQL statements for deleting all models in an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module containing the models to delete.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements for deleting the models and constraints.
    """
    connection = connections[db_name or DEFAULT_DB_ALIAS]

    if BaseDatabaseSchemaEditor:
        # Django >= 1.7
        introspection = connection.introspection

        all_table_names = set(introspection.table_names())
        deleted_models = set()

        introspection = connection.introspection

        with connection.schema_editor(collect_sql=True) as schema_editor:
            for model in get_models(app):
                table_name = convert_table_name(connection,
                                                model._meta.db_table)

                if (table_name in all_table_names
                        and model not in deleted_models):
                    schema_editor.delete_model(model)
                    deleted_models.add(model)

        return schema_editor.collected_sql
    else:
        # Django < 1.7
        style = color.no_style()

        return sql_utils.sql_delete(app, style, connection)
Esempio n. 8
0
def sql_delete(app, db_name=None):
    """Return SQL statements for deleting all models in an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module containing the models to delete.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements for deleting the models and constraints.
    """
    connection = connections[db_name or DEFAULT_DB_ALIAS]

    if BaseDatabaseSchemaEditor:
        # Django >= 1.7
        all_table_names = set(connection.introspection.table_names())
        deleted_models = set()

        introspection = connection.introspection

        with connection.schema_editor(collect_sql=True) as schema_editor:
            for model in get_models(app):
                table_name = introspection.table_name_converter(
                    model._meta.db_table)

                if (table_name in all_table_names and
                    model not in deleted_models):
                    schema_editor.delete_model(model)
                    deleted_models.add(model)

        return schema_editor.collected_sql
    else:
        # Django < 1.7
        style = color.no_style()

        return sql.sql_delete(app, style, connection)
Esempio n. 9
0
def sql_delete(app, db_name=None):
    """Return SQL statements for deleting all models in an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module containing the models to delete.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements for deleting the models and constraints.
    """
    connection = connections[db_name or DEFAULT_DB_ALIAS]

    if BaseDatabaseSchemaEditor:
        # Django >= 1.7
        all_table_names = set(connection.introspection.table_names())
        constraints_sql = []
        models_sql = []
        deleted_models = set()
        deleted_refs = set()

        with connection.schema_editor(collect_sql=True) as schema_editor:
            for model in get_models(app, include_auto_created=True):
                temp_constraints_sql, temp_models_sql = \
                    _sql_delete_model(connection, schema_editor, model,
                                      deleted_models, deleted_refs,
                                      all_table_names)
                constraints_sql += temp_constraints_sql
                models_sql += temp_models_sql

        return constraints_sql + models_sql
    else:
        # Django < 1.7
        style = color.no_style()

        return sql.sql_delete(app, style, connection)
Esempio n. 10
0
def sql_delete(app, db_name=None):
    """Return SQL statements for deleting all models in an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module containing the models to delete.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements for deleting the models and constraints.
    """
    connection = connections[db_name or DEFAULT_DB_ALIAS]

    if BaseDatabaseSchemaEditor:
        # Django >= 1.7
        all_table_names = set(connection.introspection.table_names())
        constraints_sql = []
        models_sql = []
        deleted_models = set()
        deleted_refs = set()

        with connection.schema_editor(collect_sql=True) as schema_editor:
            for model in get_models(app, include_auto_created=True):
                temp_constraints_sql, temp_models_sql = \
                    _sql_delete_model(connection, schema_editor, model,
                                      deleted_models, deleted_refs,
                                      all_table_names)
                constraints_sql += temp_constraints_sql
                models_sql += temp_models_sql

        return constraints_sql + models_sql
    else:
        # Django < 1.7
        style = color.no_style()

        return sql.sql_delete(app, style, connection)
Esempio n. 11
0
def create_app_sig(app, database):
    """
    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 = OrderedDict()

    for model in get_models(app):
        # Only include those models that can be synced.
        #
        # On Django 1.7 and up, we need to check if the model allows for
        # migrations (using allow_migrate_model).
        #
        # On older versions of Django, we check if the model allows for
        # synchronization to the database (allow_syncdb).
        if ((hasattr(router, 'allow_syncdb') and
             router.allow_syncdb(database, model.__class__)) or
            (hasattr(router, 'allow_migrate_model') and
             router.allow_migrate_model(database, model))):
            app_sig[model._meta.object_name] = create_model_sig(model)

    return app_sig
Esempio n. 12
0
def create_app_sig(app, database):
    """
    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 = OrderedDict()

    for model in get_models(app):
        # Only include those models that can be synced.
        #
        # On Django 1.7 and up, we need to check if the model allows for
        # migrations (using allow_migrate_model).
        #
        # On older versions of Django, we check if the model allows for
        # synchronization to the database (allow_syncdb).
        if ((hasattr(router, 'allow_syncdb')
             and router.allow_syncdb(database, model.__class__))
                or (hasattr(router, 'allow_migrate_model')
                    and router.allow_migrate_model(database, model))):
            app_sig[model._meta.object_name] = create_model_sig(model)

    return app_sig
Esempio n. 13
0
def sql_create_app(app, db_name=None):
    """Return SQL statements for creating all models for an app.

    This provides compatibility with all supported versions of Django.

    Args:
        app (module):
            The application module.

        db_name (str, optional):
            The database connection name. Defaults to the default database
            connection.

    Returns:
        list:
        The list of SQL statements used to create the models for the app.
    """
    # On Django >= 1.7, models for a M2M field will be created automatically,
    # so we don't want to include them in any results.
    #
    # On Django < 1.7, we need to explicitly return these models.
    models = get_models(app, include_auto_created=apps is None)

    return sql_create_models(models, db_name=db_name)
Esempio n. 14
0
def execute_test_sql(start, end, sql, debug=False, app_label='tests',
                     database='default', database_sig=None, return_sql=False,
                     rescan_indexes=True):
    """
    Execute a test SQL sequence. This method also creates and destroys the
    database tables required by the models registered against the test
    application.

    start and end are the start- and end-point states of the application cache.

    sql is the list of sql statements to execute.

    cleanup is a list of extra sql statements required to clean up. This is
    primarily for any extra m2m tables that were added during a test that won't
    be cleaned up by Django's sql_delete() implementation.

    debug is a helper flag. It displays the ALL the SQL that would be executed,
    (including setup and teardown SQL), and executes the Django-derived
    setup/teardown SQL.
    """
    out_sql = []

    # Set up the initial state of the app cache
    set_app_test_models(copy.deepcopy(start), app_label=app_label)

    # Install the initial tables and indicies
    execute_transaction(sql_create(evo_test, database),
                        output=debug, database=database)

    if rescan_indexes and database_sig:
        rescan_indexes_for_database_sig(database_sig, database)

    create_test_data(get_models(evo_test), database)

    # Set the app cache to the end state
    set_app_test_models(copy.deepcopy(end), app_label=app_label)

    try:
        if callable(sql):
            sql = sql()

        # Execute the test sql
        if debug:
            out_sql.extend(write_sql(sql, database))
        else:
            out_sql.extend(execute_transaction(sql, output=True,
                                               database=database))
    finally:
        # Cleanup the apps.
        delete_sql = sql_delete(evo_test, database)

        if debug:
            out_sql.append(delete_sql)
        else:
            out_sql.extend(execute_transaction(delete_sql, output=False,
                                               database=database))

    # This is a terrible hack, but it's necessary while we use doctests
    # and normal unit tests. If we always return the SQL, then the
    # doctests will expect us to compare the output of that (along with the
    # print statements).
    #
    # Down the road, everything should be redone to be standard unit tests,
    # and then we can just compare the returned SQL statements instead of
    # dealing with anything on stdout.
    if return_sql:
        return out_sql
    else:
        return None