Skip to content

Commit

Permalink
#283 index alphanumeric ordering for Tag's name (#286)
Browse files Browse the repository at this point in the history
* Create AddIndexSQL class

* Rename expressions file

* Self-review fixes
  • Loading branch information
ArtemijRodionov authored Feb 22, 2019
1 parent 355abae commit 5a9e0a8
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
3 changes: 1 addition & 2 deletions catalog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from django.utils.translation import ugettext_lazy as _
from unidecode import unidecode

from catalog.expressions import Substring
from catalog.models_expressions import Substring

SLUG_MAX_LENGTH = 50

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

# @todo #273:60m Create an index for order_by_alphanumeric query.
def order_by_alphanumeric(self):
"""Sort the Tag by name's alphabetic chars and then by numeric chars."""
return self.annotate(
Expand Down
File renamed without changes.
57 changes: 57 additions & 0 deletions catalog/models_operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from django.db.migrations.operations.base import Operation

# @todo #283:30m Group models.py, models_operations.py, models_expressions.py into the module.


class AddIndexSQL(Operation):
"""
Create a B-Tree index by given columns or expressions.
Docs: https://docs.djangoproject.com/en/1.11/ref/migration-operations/#writing-your-own
"""

reduces_to_sql = True
reversible = True

def __init__(self, name, columns, model_name):
self.name = name
self.columns = columns
self.model_name = model_name

def state_forwards(self, app_label, state):
"""We have to implement this method for Operation interface."""

def _index_name(self, table_name):
return f'{table_name}_{self.name}_idx'

def database_forwards(self, app_label, schema_editor, _, to_state):
to_model = to_state.apps.get_model(app_label, self.model_name)
if self.allow_migrate_model(schema_editor.connection.alias, to_model):
table_name = to_model._meta.db_table
schema_editor.execute(
f'CREATE INDEX {self._index_name(table_name)} ON {table_name}'
f'({", ".join(self.columns)});'
)

def database_backwards(self, app_label, schema_editor, from_state, _):
from_model = from_state.apps.get_model(app_label, self.model_name)
if self.allow_migrate_model(schema_editor.connection.alias, from_model):
table_name = from_model._meta.db_table
schema_editor.execute(
f'DROP INDEX {self._index_name(table_name)};'
)

def describe(self):
return f'Create index {self.name} for {self.model_name}'

# Django doesn't provide ability to add hooks to makemigrations.
# So we have to create migration files and add operations for
# abstract classes (like Tag) manually.
index_alphanumeric_tag_name = AddIndexSQL(
name='alphanumeric_name',
columns=[
"substring(name, '[a-zA-Zа-яА-Я]+')",
"(substring(name, '[0-9]+\.?[0-9]*')::float)"
],
model_name='tag',
)

2 comments on commit 5a9e0a8

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 5a9e0a8 Feb 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 273-b2ae754f disappeared from catalog/models.py, that's why I closed #283. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 5a9e0a8 Feb 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 283-e5be1cbf discovered in catalog/models_operations.py and submitted as #292. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.