From 94ed2f7c157a4ad2be6423c5fb4a1a99f131c0e0 Mon Sep 17 00:00:00 2001 From: Scott Walton Date: Thu, 17 Jul 2014 11:37:42 +0100 Subject: [PATCH] Added a clear command so we can remove views before running a migration --- .../management/commands/clear_pgviews.py | 28 +++++++++++++++ django_pgviews/view.py | 34 +++++++++++++++++++ setup.py | 2 +- .../test_project/viewtest/tests.py | 9 +++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 django_pgviews/management/commands/clear_pgviews.py diff --git a/django_pgviews/management/commands/clear_pgviews.py b/django_pgviews/management/commands/clear_pgviews.py new file mode 100644 index 0000000..6cc5a3e --- /dev/null +++ b/django_pgviews/management/commands/clear_pgviews.py @@ -0,0 +1,28 @@ +from optparse import make_option +import logging + +from django.core.management.base import NoArgsCommand +from django.db import models + +from django_pgviews.view import clear_views + + +log = logging.getLogger('django_pgviews.sync_pgviews') + + +class Command(NoArgsCommand): + help = """Clear Postgres views. Use this before running a migration""" + + def handle_noargs(self, **options): + """ + """ + for module in models.get_apps(): + for status, view_cls, python_name in clear_views(module): + if status == 'DROPPED': + msg = 'dropped' + else: + msg = 'not dropped' + log.info("%(python_name)s (%(view_name)s): %(msg)s" % { + 'python_name': python_name, + 'view_name': view_cls._meta.db_table, + 'msg': msg}) diff --git a/django_pgviews/view.py b/django_pgviews/view.py index f362b9c..5c48659 100644 --- a/django_pgviews/view.py +++ b/django_pgviews/view.py @@ -126,6 +126,40 @@ def create_view(connection, view_name, view_query, update=True, force=False): cursor_wrapper.close() +def clear_views(models_module): + """Remove the database views for a given models_module.""" + for name, view_cls in vars(models_module).iteritems(): + if not (isinstance(view_cls, type) and + issubclass(view_cls, View) and + hasattr(view_cls, 'sql')): + continue + + try: + cleared = clear_view( + connection, view_cls._meta.db_table) + except Exception, exc: + exc.view_cls = view_cls + exc.python_name = models_module.__name__ + '.' + name + raise + else: + yield cleared, view_cls, models_module.__name__ + '.' + name + + +def clear_view(connection, view_name): + """ + Remove a named view on connection. + """ + cursor_wrapper = connection.cursor() + cursor = cursor_wrapper.cursor + try: + cursor.execute('DROP VIEW IF EXISTS {0}'.format(view_name)) + + transaction.commit_unless_managed() + finally: + cursor_wrapper.close() + return u'DROPPED'.format(view=view_name) + + class View(models.Model): """Helper for exposing Postgres views as Django models.""" diff --git a/setup.py b/setup.py index 3b1a840..48f3e34 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='django-pgviews', - version='0.0.2', + version='0.0.3', description="Create and manage Postgres SQL Views in Django", author='Scott Walton', author_email='scott.walton@mypebble.co.uk', diff --git a/tests/test_project/test_project/viewtest/tests.py b/tests/test_project/test_project/viewtest/tests.py index 53faacc..76e4662 100644 --- a/tests/test_project/test_project/viewtest/tests.py +++ b/tests/test_project/test_project/viewtest/tests.py @@ -21,6 +21,15 @@ def test_views_have_been_created(self): count, = cur.fetchone() self.assertEqual(count, 3) + def test_clear_views(self): + call_command('clear_pgviews', *[], **{}) + with closing(connection.cursor()) as cur: + cur.execute('''SELECT COUNT(*) FROM pg_views + WHERE viewname LIKE 'viewtest_%';''') + + count, = cur.fetchone() + self.assertEqual(count, 0) + def test_wildcard_projection_gets_all_fields_from_projected_model(self): foo_user = auth.models.User.objects.create( username='foo', is_superuser=True)