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.
Django gives you two ways of performing raw SQL queries: you can use Manager. raw() to perform raw queries and return model instances, or you can avoid the model layer entirely and execute custom SQL directly. Explore the ORM before using raw SQL!
Migration is a way of applying changes that we have made to a model, into the database schema. Django creates a migration file inside the migration folder for each model to create the table schema, and each table is mapped to the model of which migration is created.
Raw SQL queries are useful if the query you want can't be expressed using LINQ. Raw SQL queries are also used if using a LINQ query is resulting in an inefficient SQL query. Raw SQL queries can return regular entity types or keyless entity types that are part of your model.
The best way I found to do this is using RunSQL:
Migrations contains the RunSQL class. To do this:
./manage.py makemigrations --empty myApp
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With