Skip to content

Commit 5a9e0a8

Browse files
#283 index alphanumeric ordering for Tag's name (#286)
* Create AddIndexSQL class * Rename expressions file * Self-review fixes
1 parent 355abae commit 5a9e0a8

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

catalog/models.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from django.utils.translation import ugettext_lazy as _
1414
from unidecode import unidecode
1515

16-
from catalog.expressions import Substring
16+
from catalog.models_expressions import Substring
1717

1818
SLUG_MAX_LENGTH = 50
1919

@@ -229,7 +229,6 @@ def __str__(self):
229229
class TagQuerySet(models.QuerySet):
230230
# @todo #273:30m Apply new order_by_alphanumeric for SE/STB.
231231

232-
# @todo #273:60m Create an index for order_by_alphanumeric query.
233232
def order_by_alphanumeric(self):
234233
"""Sort the Tag by name's alphabetic chars and then by numeric chars."""
235234
return self.annotate(
File renamed without changes.

catalog/models_operations.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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

Comments
 (0)