|
| 1 | +from django.db.migrations.operations.base import Operation |
| 2 | + |
| 3 | +# @todo #283:30m Group models.py, models_operations.py, models_expressions.py into the module. |
| 4 | + |
| 5 | + |
| 6 | +class AddIndexSQL(Operation): |
| 7 | + """ |
| 8 | + Create a B-Tree index by given columns or expressions. |
| 9 | +
|
| 10 | + Docs: https://docs.djangoproject.com/en/1.11/ref/migration-operations/#writing-your-own |
| 11 | + """ |
| 12 | + |
| 13 | + reduces_to_sql = True |
| 14 | + reversible = True |
| 15 | + |
| 16 | + def __init__(self, name, columns, model_name): |
| 17 | + self.name = name |
| 18 | + self.columns = columns |
| 19 | + self.model_name = model_name |
| 20 | + |
| 21 | + def state_forwards(self, app_label, state): |
| 22 | + """We have to implement this method for Operation interface.""" |
| 23 | + |
| 24 | + def _index_name(self, table_name): |
| 25 | + return f'{table_name}_{self.name}_idx' |
| 26 | + |
| 27 | + def database_forwards(self, app_label, schema_editor, _, to_state): |
| 28 | + to_model = to_state.apps.get_model(app_label, self.model_name) |
| 29 | + if self.allow_migrate_model(schema_editor.connection.alias, to_model): |
| 30 | + table_name = to_model._meta.db_table |
| 31 | + schema_editor.execute( |
| 32 | + f'CREATE INDEX {self._index_name(table_name)} ON {table_name}' |
| 33 | + f'({", ".join(self.columns)});' |
| 34 | + ) |
| 35 | + |
| 36 | + def database_backwards(self, app_label, schema_editor, from_state, _): |
| 37 | + from_model = from_state.apps.get_model(app_label, self.model_name) |
| 38 | + if self.allow_migrate_model(schema_editor.connection.alias, from_model): |
| 39 | + table_name = from_model._meta.db_table |
| 40 | + schema_editor.execute( |
| 41 | + f'DROP INDEX {self._index_name(table_name)};' |
| 42 | + ) |
| 43 | + |
| 44 | + def describe(self): |
| 45 | + return f'Create index {self.name} for {self.model_name}' |
| 46 | + |
| 47 | +# Django doesn't provide ability to add hooks to makemigrations. |
| 48 | +# So we have to create migration files and add operations for |
| 49 | +# abstract classes (like Tag) manually. |
| 50 | +index_alphanumeric_tag_name = AddIndexSQL( |
| 51 | + name='alphanumeric_name', |
| 52 | + columns=[ |
| 53 | + "substring(name, '[a-zA-Zа-яА-Я]+')", |
| 54 | + "(substring(name, '[0-9]+\.?[0-9]*')::float)" |
| 55 | + ], |
| 56 | + model_name='tag', |
| 57 | +) |
0 commit comments