Sortierung in Textfeldern mit Zahlen sollte natural-sort nutzen
Textfelder, die Zahlen enthalten (wie topic_code
), werden aktuell nicht korrekt sortiert.
Die aktuelle Sortierung sieht z.B. so aus.
- 1
- 10
- 2
Sollte aber folgendermaßen aussehen:
- 1
- 2
- 10
Das Problem lässt sich wahrscheinlich gut über eine andere Collation lösen. Django unterstützt seit v3.2 das db_collation
-Argument bei CharField
.
Hier sind ein paar Hinweise zu passenden Collations:
- How to treat numbers within strings as numbers when sorting ("A3" sorts before "A10", not after) bzw. das in der Antwort verlinkte Beispiel
- PostgreSQL-Doku zu ICU-Collations
Die Namen der Collations sind allerdings nicht genormt, sodass wir wahrscheinlich Datenbank-spezifische Migrationen brauchen, um sie zu konfigurieren. Außerdem müssen wir ggf. schauen, ob wir überhaupt für alle Datenbanken passende Collations wählen können. PostgreSQL ist unabdingbar, SQLite wäre schön.
Datenbank-spezifische Migrationen habe ich bereits früher einmal folgenderweise gelöst:
class DatabaseEngineMigrationSelector:
"""
Database Router implementation that skips migrations if the migration specifies
a required database engine and the currently configured database does not match.
Can be controlled through the hints dictionary in any migration like this:
# only run on PostgreSQL
migrations.RunSQL(
...,
hints=dict(required_database_engine='postgresql'),
)
"""
def allow_migrate(
self,
db,
app_label,
required_database_engine: typing.Union[set[str], str, None] = None,
**hints,
):
if required_database_engine is not None:
from django.conf import settings
if isinstance(required_database_engine, str):
required_database_engine = {required_database_engine}
used_engine_name = settings.DATABASES[db]["ENGINE"].rsplit(".", 1)[1]
should_execute = any(engine in used_engine_name for engine in required_database_engine)
if not should_execute:
logging.warning(
f"Skipping a migration because the current database engine "
f"does not match the database engine required for its execution. "
f"{' or '.join(required_database_engine)} was required, "
f"but {used_engine_name} is configured."
)
return False
return None
# in django settings
DATABASE_ROUTERS = ["path.to.module.DatabaseEngineMigrationSelector"]