0

私はレガシーデータベースで立ち往生しています。dbを上手に操作するために、デフォルトのクエリセットを変更したいのですが、これを行うには、を使用する必要がありますGROUP BY。私はこれができることを知っています。これにより、私が求めているSQLを取得できます。

query = Variant.objects.all().query
query.group_by = ['name']
return QuerySet(query=query, model=Variant)

そして、これは私が求めているクエリセットになります。そこで、私は私を助けるためにクエリセットマネージャを構築しました。問題は、それが正しい値を返しているということですが、私がそれを数えるとき、それは間違っています。

class VariantQuerySet(QuerySet):
    def group_by_name(self):
        self.query.group_by = ['name']
        return self.filter()

class VariantManager(models.Manager):

    def get_query_set(self):
        return VariantQuerySet(self.model, using=self._db)

しかし、それから私がそれで遊び始めるとき..

>>> Variant.objects.filter(project__name__icontains="zam")
[<Variant: RevA>, <Variant: RevA>, <Variant: RevA>, <Variant: revB>, <Variant: RevC_Fiendish>, <Variant: RevA>, <Variant: RevA_tapeout>]
>>> Variant.objects.filter(project__name__icontains="zam").count()
7
>>> Variant.objects.filter(project__name__icontains="zam").group_by_name()
[<Variant: RevA>, <Variant: revB>, <Variant: RevC_Fiendish>, <Variant: RevA_tapeout>]

ここまでは順調ですね。グループ化されていない7つのアイテム、グループ化された4つのアイテム。

>>> Variant.objects.filter(project__name__icontains="zam").group_by_name().count()
7

では、なぜ私のカウントはまだ7のままです-それは4でなければなりませんか?_result_cacheが値を保持していると思ったので、メソッドでそれをNoneに設定しましたが、運がありませんでした。これが間違っている理由はありますか?

4

1 に答える 1

1

.count()実際には、フィールドが削除されて。に置き換えられた新しいクエリが作成されますCOUNT(*)。プレーンSQLでフィールドごとにグループ化し、グループ化されたテーブルをカウントすることは実際には不可能です。基本的に、元のクエリはSQLでは次のようになりました。

SELECT myapp_variant.id, myapp_variant.name, myapp_variant.etc, ...
FROM myapp_variant inner join myapp_project on myapp_variant.project_id = myapp_project.id
WHERE myapp_project.name='zam'
GROUP BY myapp_variant.name

カウントクエリは次のようになります。

SELECT COUNT(*)
FROM myapp_variant inner join myapp_project on myapp_variant.project_id = myapp_project.id
WHERE myapp_project.name='zam'

グループ化できなくなったことに注意してください。もしそうなら、あなたは次の結果セットになってしまうでしょう:

COUNT
-----
    4 
    1
    1
    1

(この場合、4はRevAレコードの数であり、他の各レコードは1です)

集計クエリでグループ化する場合、グループ化された各列の一意の値ごとに行を作成するようにSQLに指示しているためです。4つの異なるバリアント名、つまり4つのレコード!これはあなたが望むものではありません

Djangoが生成するクエリを出力することで、これが問題であるかどうかを確認できます。

>>> print Variant.objects.filter(project__name__icontains="zam").group_by_name().query

>>> print Variant.objects.filter(project__name__icontains="zam").group_by_name().count().query

この問題には、実際には2つの解決策しかありません。

  1. group_by_nameを書き直して、フィールドでグループ化するのではなく、名前ごとに1つのレコードだけを持つフィルター処理されたクエリセットを実際に返すようにします。やるのが難しい
  2. グループ化されたクエリセットの「カウント」が必要な場合は、len()代わりに次のように使用します。

    len(Variant.objects.filter(project__name__icontains="zam").group_by_name())
    

    または、テンプレートの場合:

    {{ grouped_variants|length }}
    
于 2012-07-13T15:46:03.977 に答える