Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#283 index alphanumeric ordering for Tag's name #286

Merged
merged 3 commits into from
Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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."""
Copy link
Collaborator

Choose a reason for hiding this comment

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

in my taste just pass is enough. It's up to you


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',
)