I am aware of the cursor object in Django. Is there any other preferred way to execute raw SQL in migrations? I want to introduce postgresql partitioning for one of my models tables. The partition logic is a bunch of functions and triggers that have to be added to the database on setup which I'd like to automate.
2 Answers
One way:
The best way I found to do this is using RunSQL:
Migrations contains the RunSQL class. To do this:
./manage.py makemigrations --empty myApp
- edit the created migrations file to include:
operations = [
migrations.RunSQL('RAW SQL CODE')
]
As Nathaniel Knight mentioned, RunSQL
also accepts a reverse_sql
parameter for reversing the migration. See the docs for details
Another way
The way I solved my problem initially was using the post_migrate
signal to call a cursor to execute my raw SQL.
What I had to add to my app was this:
in the __init__.py
of myApp add:
default_app_config = 'myApp.apps.MyAppConfig'
Create a file apps.py
:
from django.apps import AppConfig
from django.db.models.signals import post_migrate
from myApp.db_partition_triggers import create_partition_triggers
class MyAppConfig(AppConfig):
name = 'myApp'
verbose_name = "My App"
def ready(self):
post_migrate.connect(create_partition_triggers, sender=self)
New file db_partition_triggers.py
:
from django.db import connection
def create_partition_triggers(**kwargs):
print ' (re)creating partition triggers for myApp...'
trigger_sql = "CREATE OR REPLACE FUNCTION...; IF NOT EXISTS(...) CREATE TRIGGER..."
cursor = connection.cursor()
cursor.execute(trigger_sql)
print ' Done creating partition triggers.'
Now on every manage.py syncdb
or manage.py migrate
this function is called. So make sure it uses CREATE OR REPLACE
and IF NOT EXISTS
. So it can handle existing functions.

- 13,380
- 9
- 75
- 96
-
Is there a way to add backwards-migration for suctom sql? – DataGreed Nov 20 '15 at 15:55
-
You should really move your note about RunSQL to the top. It's absolutely the best way to do this... – Dan Passaro Jan 20 '17 at 17:13
-
@DataGreed Not sure if you still want to know, but you can pass a 2nd SQL string to be used as the reverse sql. – LarrikJ Mar 22 '17 at 18:16
-
Note that RunSQL requires installation of the sqlparse library. – LarrikJ Mar 22 '17 at 18:16
-
2For the record, `RunSQL` also accepts a `reverse_sql` parameter for reversing the migration. See the docs for details: https://docs.djangoproject.com/en/1.11/ref/migration-operations/#runsql – Nat Knight Oct 03 '17 at 07:15
-
I want to manually add a complex constraint in a Postgresql table with RunSQL (not natively supported by Django). How do I get my SQL query to run after the other operations (notably after the creation of all tables)? – scūriolus Jan 12 '23 at 12:30
I would recommend django-migrate-sql-deux https://pypi.org/project/django-migrate-sql-deux/
This way you can manage database objects like views, functions, triggers in declarative way like models in Django. Then you need generate changes into Django migrations through makemigrations
. And apply them via migrate
. So the development and deploy flow is pretty same.
It would be awesome if Django would have this system for raw SQL "models" and handle migrations and dependencies automatically in makemigrations
and migrate
commands like django-migrate-sql-deux.

- 1,641
- 4
- 22
- 34