From 3cc325f79b275ebf6b9a3a9b37816ffaf0b96c8d Mon Sep 17 00:00:00 2001 From: Michael Trier Date: Tue, 10 Jun 2008 13:21:40 -0400 Subject: [PATCH] corrected syncdb to run app management files prior to creating tables. Also added ability to fire signals on after-create. --- .../management/commands/syncdb.py | 19 ++++++++++++++++--- django_sqlalchemy/management/sql.py | 19 +++++++++++++++++++ django_sqlalchemy/utils.py | 19 ++++++++++++++++++- tests/apps/settings.py | 2 +- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/django_sqlalchemy/management/commands/syncdb.py b/django_sqlalchemy/management/commands/syncdb.py index d95d96e..47b8604 100644 --- a/django_sqlalchemy/management/commands/syncdb.py +++ b/django_sqlalchemy/management/commands/syncdb.py @@ -1,5 +1,7 @@ from optparse import make_option +from django.conf import settings from django.core.management.base import NoArgsCommand +from django_sqlalchemy.utils import CreationSniffer class Command(NoArgsCommand): option_list = NoArgsCommand.option_list + ( @@ -16,8 +18,19 @@ def handle_noargs(self, **options): from django.core.management import call_command from django.core.management.sql import emit_post_sync_signal - # TODO: create after_create listeners for all tables, capture - # who got created and then use that in a post sync signal + # Import the 'management' module within each installed app, to register + # dispatcher events. + for app_name in settings.INSTALLED_APPS: + try: + __import__(app_name + '.management', {}, {}, ['']) + except ImportError, exc: + if not exc.args[0].startswith('No module named management'): + raise + + # set up table listeners + sniffer = CreationSniffer() + for table in metadata.tables.values(): + table.append_ddl_listener('after-create', sniffer) metadata.create_all() session.commit() @@ -27,7 +40,7 @@ def handle_noargs(self, **options): # Send the post_syncdb signal, so individual apps can do whatever they need # to do at this point. - # emit_post_sync_signal(created_models, verbosity, interactive) + emit_post_sync_signal(sniffer.models, verbosity, interactive) # load fixtures call_command('loaddata', 'initial_data', verbosity=verbosity) diff --git a/django_sqlalchemy/management/sql.py b/django_sqlalchemy/management/sql.py index c05a02d..dffb8b6 100644 --- a/django_sqlalchemy/management/sql.py +++ b/django_sqlalchemy/management/sql.py @@ -1,4 +1,5 @@ from django.db.models.loading import get_models +from django.core.management.sql import custom_sql_for_model from sqlalchemy import create_engine from django_sqlalchemy.backend import metadata, session @@ -16,3 +17,21 @@ def _get_tables_for_app(app): tables.append(model.__table__) tables.extend([f.__table__ for f in model._meta.local_many_to_many]) return tables + +def process_custom_sql(models, verbosity): + # TODO: complete this + # install custom sql for the specified models + for model in models: + custom_sql = custom_sql_for_model(model) + if custom_sql: + if verbosity >= 1: + print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name) + try: + for sql in custom_sql: + cursor.execute(sql) + except Exception, e: + sys.stderr.write("Failed to install custom SQL for %s.%s model: %s" % \ + (app_name, model._meta.object_name, e)) + transaction.rollback_unless_managed() + else: + transaction.commit_unless_managed() diff --git a/django_sqlalchemy/utils.py b/django_sqlalchemy/utils.py index 1853627..cdf98d0 100644 --- a/django_sqlalchemy/utils.py +++ b/django_sqlalchemy/utils.py @@ -1,7 +1,20 @@ import types from django.conf import settings +from django.core.management.sql import installed_models + +__all__ = 'parse_db_uri', 'db_url', 'db_label', 'CreationSniffer' + +class CreationSniffer(object): + def __init__(self): + self.tables = set() + + def __call__(self, event, table, bind): + self.tables.add(table) + + @property + def models(self): + return installed_models([table.name for table in self.tables]) -__all__ = 'parse_db_uri', 'db_url', 'db_label' def parse_db_uri(): """ @@ -12,6 +25,7 @@ def parse_db_uri(): return (db_url, db_label) db_url, db_label = parse_db_uri() + def unbound_method_to_callable(func_or_cls): """Adjust the incoming callable such that a 'self' argument is not required.""" if isinstance(func_or_cls, types.MethodType) and not func_or_cls.im_self: @@ -19,6 +33,7 @@ def unbound_method_to_callable(func_or_cls): else: return func_or_cls + def MixIn(klass, mixin, include_private=True, ancestor=False): if ancestor: if mixin not in klass.__bases__: @@ -40,9 +55,11 @@ def MixIn(klass, mixin, include_private=True, ancestor=False): member = member.im_func setattr(klass, name, member) + class MethodContainer(object): pass + class ClassReplacer(object): def __init__(self, klass, metaclass=None): self.klass = klass diff --git a/tests/apps/settings.py b/tests/apps/settings.py index e58f739..5d8cf07 100644 --- a/tests/apps/settings.py +++ b/tests/apps/settings.py @@ -12,7 +12,7 @@ 'django_sqlalchemy', # 'apps.blog', 'apps.events', - # 'django.contrib.auth', + 'django.contrib.auth', # 'apps.news', # 'apps.norelations', # 'apps.categories',