3

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

Base_Activity:
    some fields

User_Activity:
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    activity = models.ForeignKey(Base_Activity)
    rating = models.IntegerField(default=0) #Will be -1, 0, or 1

ここで、Base_Activity にクエリを実行し、最も対応するユーザー アクティビティを持つ項目を rating=1 で並べ替えます。以下のクエリのようなことをしたいのですが、その=1部分が明らかに機能していません。

activities = Base_Activity.objects.all().annotate(
    up_votes = Count('user_activity__rating'=1),
).order_by(
    'up_votes'
)

どうすればこれを解決できますか?

4

1 に答える 1

1

Countエラーメッセージが示すように、そのように使用することはできません:

SyntaxError: キーワードを式にすることはできません

の引数はCount、 のような単純な文字列でなければなりませんuser_activity__rating

Avg良い代替手段は、 と を一緒に使用することだと思いますCount:

activities = Base_Activity.objects.all().annotate(
    a=Avg('user_activity__rating'), c=Count('user_activity__rating')
).order_by(
    '-a', '-c'
)

アクティビティが最も多いアイテムはrating=1平均が最も高く、平均が同じユーザーの中で最もアクティビティが多いアイテムが上位に表示されます。

反対票のある項目を除外する場合は、 の後に適切なfilterまたはexclude操作を追加してくださいannotate。次に例を示します。

activities = Base_Activity.objects.all().annotate(
    a=Avg('user_activity__rating'), c=Count('user_activity__rating')
).filter(user_activity__rating__gt=0).order_by(
    '-a', '-c'
)

アップデート

反対票を無視して、賛成票順に並べられたすべてのアイテムを取得するには、次のように生のクエリを使用するしかないと思います。

from django.db import connection

sql = '''
SELECT o.id, SUM(v.rating > 0) s
FROM user_activity o
JOIN rating v ON o.id = v.user_activity_id
GROUP BY o.id ORDER BY s DESC
'''
cursor = connection.cursor()
result = cursor.execute(sql_select)
rows = result.fetchall()

注: モデルのテーブル名をハードコーディングする代わりに、モデルからテーブル名を取得します。たとえば、モデルが と呼ばれている場合、Ratingそのテーブル名を で取得できますRating._meta.db_table

このクエリを sqlite3 データベースでテストしましたが、SUMそこにある式がすべての DBMS で機能するかどうかはわかりません。ところで、テストするのに最適な Django サイトがありました。ここでは、賛成票と反対票も使用しています。賛成票と反対票をカウントするために非常によく似たモデルを使用しますが、それらをsum値、stackoverflow スタイルで並べ替えます。興味があれば、このサイトオープンソースです。

于 2013-10-18T18:19:16.970 に答える