Django: Bestellung numerischen Wert mit order_by
Ich bin in einer situation, wo muss ich die Ausgabe in einer Recht großen Liste von Objekten, die durch eine CharField zum speichern von Adressen.
Mein problem ist, dass offensichtlich die Daten bestellt von ASCII-codes, da es ein Charfield, mit dem vorhersagbaren Ergebnis .. es sortiert die zahlen wie folgt;
1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 21....
Jetzt die offensichtliche Schritt wäre die änderung der Charfield das richtige Feld Typ (IntegerField sagen wir mal), aber es kann nicht funktionieren, da einige Adresse haben könnte, apartments .. wie "128A".
Ich weiß wirklich nicht, wie ich kann, um dies richtig ..
- Neugierig zu wissen, ob Sie eine Lösung gefunden, um dieses. Vielen Dank. N
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn du sicher bist, es sind nur ganze zahlen in das Feld ein, Sie erhalten konnten, die Datenbank zu casten als integer über den
extra
Methode, und, um durch das:extra()
, hier ist, wie zu tun die gleiche Sache mitannotate()
:MyModel.objects.annotate(myinteger=RawSQL('CAST(mycharfield AS UNSIGNED)', params=[])).order_by('myinteger')
Wenn Sie mit PostgreSQL (nicht sicher über die MySQL) Sie können sicher verwenden Sie folgenden code auf char/text-Felder und vermeiden cast Fehler:
Django versucht, missbilligen die
extra()
Methode, aber eingeführt hatCast()
in v1.10. In sqlite (zumindest)CAST
können einen Wert wie10a
und werfe es auf den integer -10
, so dass Sie tun können:wird wieder Objekte sortiert, indem die Hausnummer zuerst numerisch dann alphabetisch, z.B.
...14, 15a, 15b, 16, 16a, 17...
Cast
nicht unterstützt Werte wie10a
. Wenn es einen bekommt, wirft esDataError: invalid input syntax for integer
. Ich fand einen workaround, indem Sie alle Zeichen in dem Wert, die nicht zahlen (PostgreSQL):from django.db.models.expressions import F, Value, Func
queryset.annotate(my_integer_field=Cast( Func(F('my_char_field'), Value('[^\d]'), Value(''), Value('g'), function='regexp_replace'), IntegerField()) )
Super Tipp! Es funktioniert für mich! 🙂 Das ist mein code:
Das problem, das Sie sind gegen ist ganz ähnlich wie Dateinamen bekommen, bestellt bei der Sortierung nach dem Dateinamen. Dort, Sie wollen "2 Foo.mp3" angezeigt, bevor "12 Foo.mp3".
Einem gemeinsamen Konzept zu "normalisieren" zahlen zu erweitern, um eine Feste Anzahl von Ziffern, und dann die Sortierung basiert auf der normalisierten form. Das heißt, für Zwecke der Sortierung, "2 Foo.mp3" - möglicherweise zu erweitern, um "0000000002 Foo.mp3".
Django nicht helfen Sie direkt hier. Sie können entweder fügen Sie ein Feld zum speichern der "normalized" - Adresse, und habe die Datenbank
order_by
dass, oder Sie können eine benutzerdefinierte Sortierung in der Ansicht (oder in einem Helfer, dass Ihre Ansicht verwendet) auf Adresse Aufzeichnungen vor der übergabe der Liste von Datensätzen zu einer Vorlage.In Fall müssen Sie Sie Sortieren Versionsnummern aus mehreren Ziffern, getrennt durch einen Punkt (z.B.
1.9.0, 1.10.0
), hier ist ein postgres-einzige Lösung:In Fall, dass Sie wollen, um zu erlauben, dass nicht-numerische Zeichen (z.B.
0.9.0 beta
,2.0.0 stable
):War ich auf der Suche nach einem Weg, um die Sortierung der numerischen chars in einer
CharField
und meine Suche hat mich hierher geführt. Diename
Felder in der meine Objekte sind CC-Lizenzen, z.B. "CC BY-NC 4.0'.Seit
extra()
wird nicht mehr verwendet, ich war in der Lage, es zu tun auf diese Weise:So
MyObject
mitname='CC BY-NC 4.0'
jetzt hatsorting_int=40
.