Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pgtrigger causes exceptions when reversing migrations #29

Closed
shangxiao opened this issue Jul 21, 2021 · 3 comments
Closed

pgtrigger causes exceptions when reversing migrations #29

shangxiao opened this issue Jul 21, 2021 · 3 comments
Labels
bug Something isn't working

Comments

@shangxiao
Copy link

pgtrigger attempts to create triggers using the post migrate signal – this signal is fired for forwards and reverse migrations. This is problematic as it is possible pgtrigger will attempt to create a trigger on a non-existent table, causing exceptions and preventing subsequent post-migrate signals from being fired.

Example:

Simple test model:

@pgtrigger.register(pgtrigger.Protect(name="cant_delete", operation=pgtrigger.Delete))
class TestModel(models.Model):
    ...

Running forwards, then reverse migrations:

$ ./manage.py migrate test_pg_trigger
Operations to perform:
  Apply all migrations: test_pg_trigger
Running migrations:
  Applying test_pg_trigger.0001_initial... OK

$ ./manage.py migrate test_pg_trigger zero
Operations to perform:
  Unapply all migrations: test_pg_trigger
Running migrations:
  Rendering model states... DONE
  Unapplying test_pg_trigger.0001_initial... OK
Traceback (most recent call last):
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
psycopg2.errors.UndefinedTable: relation "test_pg_trigger_testmodel" does not exist
CONTEXT:  SQL statement "CREATE TRIGGER pgtrigger_cant_delete_7dbde
                    BEFORE DELETE ON test_pg_trigger_testmodel

                    FOR EACH ROW
                    EXECUTE PROCEDURE pgtrigger_cant_delete_7dbde()"
PL/pgSQL function inline_code_block line 2 at SQL statement


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/path/to/project/./manage.py", line 22, in <module>
    main()
  File "/path/to/project/./manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
    output = self.handle(*args, **options)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/base.py", line 89, in wrapped
    res = handle_func(*args, **kwargs)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/commands/migrate.py", line 268, in handle
    emit_post_migrate_signal(
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/core/management/sql.py", line 46, in emit_post_migrate_signal
    models.signals.post_migrate.send(
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 170, in send
    return [
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 171, in <listcomp>
    (receiver, receiver(signal=self, sender=sender, **named))
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/pgtrigger/apps.py", line 9, in install
    pgtrigger.install(database=using)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/pgtrigger/core.py", line 903, in install
    trigger.install(model)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/pgtrigger/core.py", line 657, in install
    cursor.execute(rendered_trigger)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/backends/utils.py", line 98, in execute
    return super().execute(sql, params)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/backends/utils.py", line 66, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/path/to/project/.direnv/python-3.9.0/lib/python3.9/site-packages/django/db/backends/utils.py", line 82, in _execute
    return self.cursor.execute(sql)
django.db.utils.ProgrammingError: relation "test_pg_trigger_testmodel" does not exist
CONTEXT:  SQL statement "CREATE TRIGGER pgtrigger_cant_delete_7dbde
                    BEFORE DELETE ON test_pg_trigger_testmodel

                    FOR EACH ROW
                    EXECUTE PROCEDURE pgtrigger_cant_delete_7dbde()"
PL/pgSQL function inline_code_block line 2 at SQL statement
@wesleykendall
Copy link
Member

@shangxiao thanks for bringing this one up. I believe that we might have the same issue for triggers with conditions on columns that are deleted too. Unfortunately there is no easy and complete fix for this until it is completely integrated with the migration system, which I will elaborate on more at #25

One possible thing I can do here is to at least ignore creating triggers when the table doesn't exist. I will need to think about it a bit more, but I don't believe there are any ramifications of doing this simple check.

@wesleykendall
Copy link
Member

FYI @shangxiao I'm going to be actively keeping #25 up to date since I will be implementing the installation of triggers in Django migrations.

I will keep this current issue open and close it after it has been resolved. For now, follow #25 for generating triggers in django migrations

@wesleykendall
Copy link
Member

@shangxiao triggers are now integrated into the migration system and #25 is closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants