2015-09-03 2 views
8

Я пытаюсь использовать перенос Django migrations.RunSQL для запуска произвольного кода SQL. Я хотел бы запустить эту миграцию только для определенных баз данных db (например, только для postgres).Django Migration RunSQL Conditional on Database Type

Я бы подумал to use something like this, но я не вижу информацию о подключении БД в классе Migration.

ответ

0

Эта информация не указана в классе Migration, она предоставляется в атрибуте schema_editor, переданном в RunPython. См. the documentation для некоторых примеров использования этого.

4

У меня была такая же потребность. Мне пришлось отредактировать миграцию, которая устанавливает начальное значение последовательности, которая работает на postgres, но не sqlite. Вот как я обернул RunSQL внутри RunPython, следуя документации, связанной с Даниэлем.

from django.db import migrations 


def forwards(apps, schema_editor): 
    if not schema_editor.connection.vendor == 'postgres': 
     return 
    migrations.RunSQL(
     "alter sequence api_consumer_id_seq restart with 1000500;") 


class Migration(migrations.Migration): 
    dependencies = [ 
     ('api', '0043_auto_20160416_2313'), 
    ] 

    operations = [ 
     migrations.RunPython(forwards), 
    ] 
+1

Моя строка поставщика был 'postgresql' и не' postgres' (в Django 1.10.6) –

+0

Проблема с этим состоит в том, что 'migrations.RunSQL()' возвращает объект. Он фактически не выполняет какой-либо SQL до тех пор, пока не будет вызван метод '_run_sql()' этого объекта с определенными параметрами. См. Ответ PaulMest для решения, которое также использует метод 'migrations.RunPython()', но выполняет SQL таким образом, который фактически выполняет SQL. – radicalbiscuit

3

я решил подобную проблему сегодня - необходимости выполнить миграцию, чтобы создать новую модель, но только для БД Postgres - и я нашел этот вопрос. Однако ответ Мэтью не помог мне. На самом деле, я не уверен, что он работает вообще. Это потому, что строка с migrations.RunSQL(...) фактически не run SQL; он создает новый объект типа RunSQL, который является Command, а затем сразу же отбрасывает его.

Вот как я в конечном итоге решить эту проблему, в случае, если кто-то пытается искать «Джанго условной миграции» в будущем:

from __future__ import unicode_literals 

import django.contrib.postgres.fields 
from django.db import migrations, models 


class PostgresOnlyCreateModel(migrations.CreateModel): 
    def database_forwards(self, app_label, schema_editor, from_state, to_state): 
     if schema_editor.connection.vendor.startswith("postgres"): 
      super(PostgresOnlyCreateModel, self).database_forwards(app_label, schema_editor, from_state, to_state) 

    def database_backwards(self, app_label, schema_editor, from_state, to_state): 
     if schema_editor.connection.vendor.startswith("postgres"): 
      super(PostgresOnlyCreateModel, self).database_backwards(app_label, schema_editor, from_state, to_state) 


class Migration(migrations.Migration): 

    dependencies = [ 
     ...whatever... 
    ] 

    operations = [ 
     PostgresOnlyCreateModel(
      name='...whatever...', 
      fields=[...whatever...], 
     ), 
    ] 
4

Вот как я решил эту проблему, так как я не мог получить RunSQL для работы внутри RunPython. К счастью, объект schema_editor имеет execute() method.

def forwards(apps, schema_editor): 
    if not schema_editor.connection.vendor.startswith('postgres'): 
     logger.info('Database vendor: {}'.format(schema_editor.connection.vendor)) 
     logger.info('Skipping migration without attempting to ADD CONSTRAINT') 
     return 

    schema_editor.execute('ALTER TABLE my_table ADD CONSTRAINT my_constraint (my_field != \'NaN\';)') 


def backwards(apps, schema_editor): 
    if not schema_editor.connection.vendor.startswith('postgres'): 
     logger.info('Database vendor: {}'.format(schema_editor.connection.vendor)) 
     logger.info('Skipping migration without attempting to DROP CONSTRAINT') 
     return 

    schema_editor.execute('ALTER TABLE my_table DROP CONSTRAINT my_constraint;') 


class Migration(migrations.Migration): 

    dependencies = [ 
     ... 
    ] 

    operations = [ 
     migrations.RunPython(forwards, backwards, atomic=True) 
    ] 
+0

Это сработало для меня, за исключением того, что мне нужно иметь атомный = False – kzh

+0

Будьте осторожны с 'atomic = False'. Если некоторые действия преуспевают, а другие терпят неудачу, ваша база данных может оказаться в несогласованном состоянии. – PaulMest

+0

Django отказался бы запустить его для меня иначе. – kzh