djangoで個別の列をDISTINCTしますか?


93

SELECT * FROM...下に" "ではないクエリをDjangoで実行する方法があるかどうか知りたいです。SELECT DISTINCT columnName FROM ...代わりに" " を実行しようとしています。

具体的には、次のようなモデルがあります。

class ProductOrder(models.Model):
   Product  = models.CharField(max_length=20, promary_key=True)
   Category = models.CharField(max_length=30)
   Rank = models.IntegerField()

ここで、Rankは内のランクCategoryです。そのカテゴリ内の各ランクで何らかの操作を実行しているすべてのカテゴリを反復処理できるようにしたいと思います。

最初にシステム内のすべてのカテゴリのリストを取得してから、そのカテゴリ内のすべての製品をクエリし、すべてのカテゴリが処理されるまで繰り返します。

生のSQLは避けたいですが、そこに行かなければならない場合は問題ありません。Django / Pythonで生のSQLをコーディングしたことはありませんが。

回答:


185

データベースから個別の列名のリストを取得する1つの方法はdistinct() 、と組み合わせて使用することvalues()です。

あなたの場合、あなたは別個のカテゴリーの名前を得るために以下を行うことができます:

q = ProductOrder.objects.values('Category').distinct()
print q.query # See for yourself.

# The query would look something like
# SELECT DISTINCT "app_productorder"."category" FROM "app_productorder"

ここで覚えておくべきことがいくつかあります。まず、これはValuesQuerySetとは異なる動作をするを返しQuerySetます。sayにアクセスすると、q(上記)の最初の要素はのインスタンスではなくディクショナリを取得しますProductOrder

次に、の使用に関するドキュメントの警告メモを読むことをお勧めしますdistinct()。上記の例は機能しますが、のすべての組み合わせは機能distinct()values()ない場合があります。

PS:モデルのフィールドには小文字の名前を使用することをお勧めします。あなたの場合、これは以下に示すようにモデルを書き換えることを意味します:

class ProductOrder(models.Model):
    product  = models.CharField(max_length=20, primary_key=True)
    category = models.CharField(max_length=30)
    rank = models.IntegerField()

1
以下で説明するメソッドは、django 1.4で利用できるようになり、フィールド対応の個別のProductOrderインスタンスが必要な場合に便利です;-)
Jonathan Liuti

61

PostgreSQLを使用している場合はdistinct(columns)documentation)を使用するだけで非常に簡単です

Productorder.objects.all().distinct('category')

この機能は1.4以降Djangoに含まれていることに注意してください


@ lazerscience、@ Manoj Govindan:すみません、あなたは正しいです。その機能を追加するためにDjangoにパッチを適用したようです。パッチへのリンクを追加しました
Wolph

3
これは現在Django SVNにあり、Django 1.4に含まれます
Will Hardy

14
注:PostgreSQLを使用している場合を除き、distinct()に引数を与えることはできません。上記の承認されたソリューションを使用するのが最善です。
Mark Chackerian、2013

テストでは、これはcan_distinct_on_fieldsPostgresのみであるように見えます
Skylar Saveland 2013

3
プラス1、ただしall()ここでは不要
Antony Hatchkins 2015

17

他の答えは問題ありませんが、Djangoからの残骸がなく、DISTINCTクエリから得られるような値のみを提供するという点で、これは少しクリーンです。

>>> set(ProductOrder.objects.values_list('category', flat=True))
{u'category1', u'category2', u'category3', u'category4'}

または

>>> list(set(ProductOrder.objects.values_list('category', flat=True)))
[u'category1', u'category2', u'category3', u'category4']

そして、それはPostgreSQLなしで動作します。

これは.distinct()を使用するよりも効率的ではありません。データベース内のDISTINCTはpythonよりも高速であると想定していますがset、シェルの周りを移動するには最適です。


values_listDISTINCTsqlクエリに入れないため、複数の値が存在する場合はこれが表示されます。
メフメット2016年

13

ユーザーはそのフィールドを使用して注文し、それから区別します。

ProductOrder.objects.order_by('category').values_list('category', flat=True).distinct()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.