11

値が少数の選択肢に制限されているCharFieldを持つモデルShirtsを想像してください。たとえば、「小」、「中」、「大」、「x大」などです。size

シャツをサイズ別にグループ化するには、次のようにします。

Shirts.objects.order_by('size')

ただし、Djangoは(当然のことながら)グループをアルファベット順に並べます。つまり、「大」、「中」、「小」、「xlarge」の順になります。私が欲しいのは、「大」の前に「中」の前に「小」を置くことです。

つまり、私が自然にやりたいことは、次の擬似コードのようなものです。

size_order = {'small': 1, 'medium': 2, 'large': 3, 'xlarge': 4}
Shirts.objects.order_by('size_order[size]')

これを達成するための最良の方法は何ですか?

編集:さまざまな提案されたアプローチについての考えについては、以下の回答に対する私のコメントを参照してください。調査しているSQLORDERBYCASE構文を使用したカスタムManager/QuerySetアプローチに遭遇しました。

4

5 に答える 5

11

私が探しているものに最も近いものを見つけました。それはQuerySet.extra()、Djangoが直接サポートしていないSQLのCASE WHEN/THEN構文を利用するためにメソッドを使用することです。

CASE_SQL = '(case when size="small" then 1 when size="medium" then 2 when size="large" then 3 when size="xlarge" then 4 end)' 
Shirt.objects.extra(select={'shirt_order': CASE_SQL}, order_by=['shirt_order'])

私の(人工的な)例を考えると、これはやり過ぎや厄介に思えるかもしれませんが、それは私が探していたトリックです!この問題に対する他の完全に有効なアプローチをみんなに感謝します。それはどういうわけか間接的にこのアプローチを理解するきっかけになりました。

PSSQLのCASEWHEN/ THEN構文を介して、この種のカスタム順序付けのためのよりネイティブなDjangoインターフェイスを提供するカスタムモデルManager / QuerySetコンボを作成したくなりますが、それは別の機会に宿題として残しておきます。

注:CASE WHEN / THENの構文は、データベース固有です。上記の構文はSQLite用です。PostgreSQLの場合、括弧を省略し、二重引用符の代わりにエスケープされた一重引用符を使用します。

于 2012-07-28T13:45:05.373 に答える
3

(charfieldを使用したため)可能な選択肢をハードコーディングしたくないようですが、同時に、選択肢の数が少ないと言います。

選択肢をハードコーディングすることに満足している場合は、代わりに整数フィールドに変更できます。

class Shirt(models.Model):
  SIZE_CHOICES = (
    (1, u'small'),
    (2, u'medium'),
    (3, u'large'),
    (4, u'x-large'),
    (5, u'xx-large'),
  )
  size = models.IntegerField(choices = SIZE_CHOICES)

サイズの選択をハードコーディングしたくない場合は、使用可能なサイズを別のモデルに移動して、シャツモデルの外部キーとして参照することをお勧めします。任意にソート可能にするには、ソート可能な主キー以外のソートのインデックスが必要になります。多分このようなもの:

class Size(models.Model):
  sortorder = models.IntegerField()
  name = models.CharField()
  class Meta:
    ordering = ['sortorder']
于 2012-07-27T22:07:02.647 に答える
2

size希望どおりに順序付けられた選択タプルを使用してフィールドを設定する必要があります。あなたの中models.pyには次のようなものがあります:

from django.db import models

SHIRT_SIZE_CHOICES = (
    (u"0", u"small"),
    (u"1", u"medium"),
    (u"2", u"large"),
    (u"3", u"xlarge"))

class Shirt(models.Model):
    ...
    size = models.CharField(max_length=2, choices=SHIRT_SIZE_CHOICES)

次にorder_by、意図したとおりに並べ替えます。

于 2012-07-27T21:58:48.220 に答える
2

カスタムの並べ替え関数を作成せずに、orderフィールドをモデルに追加するだけです。

class Shirt(models.Model):
    ...
    order = models.IntegerField(default=0)
    class Meta:
        ordering = ('order',)

Shirt.objects.filter(name='Awesome Shirt')

または、より適切には、と呼ばれる新しいモデルを作成しますSize

于 2012-07-28T09:51:22.630 に答える
1

フィールド値を整数として格納したくない場合は、組み込みのorder_by()メソッドでカスタムケースを処理できません。データを取得したら、データを並べ替えるために独自の関数を作成する必要があります。

もちろん、これを行うには、任意の値をそれぞれの順序で整数にマップしてから、その配置で並べ替えるのが最善の方法です:)。

于 2012-07-28T09:45:55.240 に答える