Search code examples
djangopostgresql-9.3django-migrationsltree

How to install an extension in PostgreSQL before creating the models in django?


Using django 1.8 + Postgres 9+, I have models with custom PG datatypes (like ltree). Creating de database from zero fail because

CREATE EXTENSION ltree;

is not executed. I try with a empty migration, but that run after the models creation. Exist a way to run sql before the models creation?


Solution

  • I know this is unanswered for long, and maybe now you already have figured out the answer. But I'm posting just in case someone gets a little bit of help from this.

    For extensions that are available in Postgres

    If the extension is one of the defaults that are available with Postgres, then you can simply create first migration as this, and then load other migrations.

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    from django.contrib.postgres.operations import HStoreExtension
    
    from django.db import migrations
    
    
    class Migration(migrations.Migration):
    
        run_before = [
            ('some_app_that_requires_hstore', '0001_initial'),
        ]
    
        operations = [
            HStoreExtension(),
        ]
    

    Notice the use of run_before. It is the exact opposite of dependencies. Alternatively, you can make this migration as say 1st one and load all others after this using dependencies.

    In case this migration fails to create an extension because of privileges issues, then you can simply use the superuser and nosuperuser in Postgres to temporarily provide privileges for the current user to run migrations like:

    ALTER ROLE user_name superuser;
    # create the extension and then remove the superuser privileges.
    ALTER ROLE user_name nosuperuser;
    

    For third-party extensions that are not available in Postgres

    For third-party extensions, you can use run_python, to load the extension for you like:

    from django.db import migrations
    
    
    def create_third_party_extension(apps, schema_editor):
        schema_editor.execute("CREATE EXTENSION my_custom_extension;")
    
    
    def drop_third_party_extension(apps, schema_editor):
        schema_editor.execute("DROP EXTENSION IF EXISTS my_custom_extension;")
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('venues', '0001_auto_20180607_1014'),
        ]
    
        operations = [
            migrations.RunPython(create_third_party_extension, reverse_code=drop_third_party_extension, atomic=True)
    ]
    

    Alternatively, you can just have them as a part of your deployment scripts instead of migrations.

    I hope this helps.