8

私は次のモデルを持っています:

class Foo(models.Model):
    pass

class Bar(models.Model):
    foo = models.ForeignKey(Foo)
    is_successful = models.BooleanField()

オブジェクトに関連付けられているすべてfooのオブジェクトがbarfoois_successfulTrue

これまでのところ、私のクエリセットは次のとおりです。

foos = Foo.objects.all().annotate(all_successful=Min('bar__is_successful'))

注釈の考え方は、すべての行all_successfulの最小値が 1 の場合、すべてのis_successful行が 1 でなければならないということです( isおよびisとTrue仮定)。したがって、クエリセットを次のように使用できることを知っています。0False1True

foo = foos[0]

if foo.all_successful == 1:
    print 'All bars are successful'
else:
    print 'Not all bars are successful'

これは sqlite ではうまく機能しますが、PostgreSQLMINではブール列に対して集計を実行できないため失敗します。sqliteはブール値を整数として扱い、集計を実行できるため、これはsqliteで機能すると思います。

is_successful私の質問は、フィールドを に変換せずに、このクエリセットを PostgreSQL で機能させるにはどうすればよいかということIntegerFieldです。

ありがとう

4

3 に答える 3

16

これは古い質問であることは知っていますが、最近これに遭遇しました。Django v1.8 には case/when のサポートが組み込まれているため、カスタム SQL をいじる代わりに ORM を使用できます。

https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/#case

Foo.objects.annotate(
    all_successful=Case(
        When(bar__is_successful=False, then=False),
        When(bar__is_successful=True, then=True),
        default=False,
        output_field=BooleanField()
    ))

私はこれを試していませんが、最近のプロジェクトで同様のことがうまくいきました。

于 2015-10-04T12:15:04.270 に答える
3

FOR DJANGO <= 1.7:取得するには、単純にExtraを使用annotationできると思います

foos = Foo.objects.extra(select={'all_successful': 'CASE WHEN COUNT(b.foo) > 0 THEN 0 ELSE 1 END FROM yourapp_bar as b WHERE b.is_successful = false and b.foo = yourapp_foo.id' })

お使いのシステムがDjango 1.8+を実行している場合は、 Dav3xor answerに従ってください。

于 2013-03-13T00:20:06.023 に答える
1

https://docs.djangoproject.com/en/dev/topics/db/managers/に触発されて、注釈の代わりに Bar クラスにカスタムマネージャーを使用することをお勧めします

class BarManager(models.Manager):
    def get_all_successful_foos_ids(self):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("""
            SELECT foo, COUNT(*)
            FROM yourapp_bar
            GROUP BY 1
            WHERE is_successful = true""")  # <-- you have to write the correct table name here
        result_list = []
        for row in cursor.fetchall():
            if row[1] > 0:
                result_list.append(row[0])
        return result_list

class Bar(models.Model):
    foo = models.ForeignKey(Foo)
    is_successful = models.BooleanField()
    objects = BarManager()  # here I'm changing the default manager

次に、コードで:

foos = foo.objects.filter(id__in=Bar.objects.get_all_successful_foos_ids())
于 2013-03-12T23:18:40.313 に答える