web-dev-qa-db-ja.com

Django

Django QuerySetsで特定の順序をどのように定義しますか?

具体的には、次のようなQuerySetがある場合:_['a10', 'a1', 'a2']_。

通常の注文(Whatever.objects.order_by('someField')を使用)では、_['a1', 'a10', 'a2']_が表示されますが、探しているのは_['a1', 'a2', 'a10']_です。

私自身の注文テクニックを定義する適切な方法は何ですか?

30
Yuval Adam

私の知る限り、データベース側の順序をこのように指定する方法はありません。バックエンド固有であるためです。古き良き時代のPython並べ替え:

class Foo(models.Model):
    name = models.CharField(max_length=128)

Foo.objects.create(name='a10')
Foo.objects.create(name='a1')
Foo.objects.create(name='a2')

ordered = sorted(Foo.objects.all(), key=lambda n: (n[0], int(n[1:])))
print ordered # yields a1, a2, 10

この種の並べ替えが必要な場合は、順序付けを実行するモデルのカスタムmodels.Managerサブクラスを作成することをお勧めします。何かのようなもの:

class FooManager(models.Manager):
    def in_a_number_order(self, *args, **kwargs):
        qs = self.get_query_set().filter(*args, **kwargs)
        return sorted(qs, key=lambda n: (n[0], int(n[1:])))

class Foo(models.Model):
    ... as before ...
    objects = FooManager()

print Foo.objects.in_a_number_order()
print Foo.objects.in_a_number_order(id__in=[5, 4, 3]) # or any filtering expression
42
Jarret Hardie

@Jarretの答え(Pythonでソートを行う)は、単純なケースに最適です。大きなテーブルがあり、たとえば、特定の方法でソートされた結果の最初のページのみをプルしたい場合、このアプローチは失敗します(ソートを実行する前に、データベースからすべての行をプルする必要があります)。その時点で、保存時に「名前」フィールドから入力する非正規化された「ソート」フィールドを追加することを検討します。これは、通常の方法でDBレベルでソートできます。

30
Carl Meyer

より大きなデータセットがあり、さらにSOLRバックエンドを使用する場合(Haystackなど):

使用する solr.ICUCollationField とともに numeric=trueソートフィールドのタイプとしてのオプション。これは言語に従ってソートされ、数値が存在する場合は、文字列ソートではなく数値規則に従って数値部分をソートします。

参照: https://cwiki.Apache.org/confluence/display/solr/Language+Analysis#LanguageAnalysis-UnicodeCollat​​ionhttp://www.solr-start.com/javadoc/ solr-lucene/org/Apache/solr/schema/ICUCollat​​ionField.html

0
Risadinha

どこで使いたいかによります。

独自のテンプレートで使用する場合は、順序付けを行うテンプレートタグを作成することをお勧めします。その中で、使用する任意の並べ替えアルゴリズムを使用できます。

管理者では、上記のようにテンプレートを必要に応じて拡張し、テンプレートタグを読み込むことでカスタム並べ替えを行います

0
vikingosegundo