27đź‘Ť
Here is how I solved the problem since I couldn’t get RunSQL
to work inside RunPython
. Thankfully, the schema_editor
object has an 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)
]
8đź‘Ť
I just had the same need. I had to edit a migration that set the initial value of a sequence, which works on postgres but not sqlite. Here’s how I wrapped the RunSQL inside a RunPython, following the documentation that Daniel linked to.
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),
]
- [Django]-Any drawbacks or gotchas to using Jinja2 templates in Django?
- [Django]-Django static files versioning
- [Django]-What does on_delete do on Django models?
6đź‘Ť
I solved a similar problem today — needing to perform a migration to create a new model, but only for a postgres DB — and I found this question. However, Matthew’s answer did not help me. In fact, I’m not sure it works at all. That is because the line with migrations.RunSQL(...)
does not actually run SQL; it creates a new object of type RunSQL
which is a Command
, and then immediately discards it.
Here’s how I ended up solving the problem, in case anyone tries to search for “django conditional migration” in the future:
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...],
),
]
- [Django]-Django error 'too many values to unpack'
- [Django]-Context processors vs middleware in django
- [Django]-How can I resize an image file uploaded with Django using an ImageField Model?
0đź‘Ť
That information is not provided in the Migration class, it is provided in the schema_editor
attribute passed to a RunPython operation. See the documentation for some examples on using this.
- [Django]-How secure is Django
- [Django]-Deploying Google Analytics With Django
- [Django]-Represent Ordering in a Relational Database
0đź‘Ť
Another option is to have the actual sql depend on db.connection.vendor:
from django.db import connection
CONCURRENTLY = "CONCURRENTLY" if connection.vendor == "postgres" else ""
SQL = f"CREATE INDEX {CONCURRENTLY}..."
At that point you can just use migrations.RunSQL
, which is handy, particularly if you use the state_operations
argument.
- [Django]-What's the best option to process credit card payments in Django?
- [Django]-Django Model set foreign key to a field of another Model
- [Django]-How do I rename a Django project in PyCharm?
0đź‘Ť
If you want to apply migrations depending on app or model, I think the best solution is using django database router.
First define a database router class:
from django.db import connections
class PgOnlyMigrateRouter:
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'pgonly_app' or model_name == 'pgonly_model':
return connections[db].vendor.startswith("postgres")
return None
Then in your setting.py file, add this line:
DATABASE_ROUTERS = ['path.to.PgOnlyMigrateRouter']
As you see, this works for all migrations in specified model or app, not just a single migration operation.
- [Django]-Get objects from a many to many field
- [Django]-What's the difference between STATIC_URL and STATIC_ROOT in Django?
- [Django]-How to link docker containers on build?