私は2つのモデルを持っています:
class Post(models.Model):
#some fields
pass
class Vote(models.Model):
post = mdoels.ForeignKey(Post)
value = models.IntegerField()
投票の値は 1 または -1 のいずれかです (ユーザーは上下に投票できます)。
評価順に並べられた投稿のリストを取得するにはどうすればよいですか?
私は2つのモデルを持っています:
class Post(models.Model):
#some fields
pass
class Vote(models.Model):
post = mdoels.ForeignKey(Post)
value = models.IntegerField()
投票の値は 1 または -1 のいずれかです (ユーザーは上下に投票できます)。
評価順に並べられた投稿のリストを取得するにはどうすればよいですか?
注釈を使用する必要があります。 https://docs.djangoproject.com/en/dev/topics/db/aggregation/
class Post(models.Model):
name = models.CharField(max_length=20)
class Vote(models.Model):
post = models.ForeignKey(Post)
value = models.IntegerField()
type = models.CharField(max_length=2, choices=(("AW", "Awesomeness"), ("US", "Usefulness")))
次に、インポートする必要があり、次のようなSum
順序で投稿のリストを取得できます。vote_total
from django.db.models import Sum
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')
編集:
ここに例があります。いくつかの投稿オブジェクトと投票オブジェクトを作成します
Post.objects.get_or_create(id=1, name="post1")
Post.objects.get_or_create(id=2, name="post2")
Post.objects.get_or_create(id=3, name="post3")
Post.objects.get_or_create(id=4, name="post4")
Vote.objects.get_or_create(id=1, post_id=2, value=1, type="AW")
Vote.objects.get_or_create(id=2, post_id=2, value=1, type="AW")
Vote.objects.get_or_create(id=3, post_id=2, value=1, type="US")
Vote.objects.get_or_create(id=4, post_id=2, value=1, type="US")
Vote.objects.get_or_create(id=5, post_id=3, value=-1, type="AW")
Vote.objects.get_or_create(id=6, post_id=3, value=-1, type="AW")
Vote.objects.get_or_create(id=7, post_id=4, value=-1, type="AW")
その後、存在posts = Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')
につながり[(post.name, post.vote_total) for post in posts]
ます。
[(u'post2', 4), (u'post4', -1), (u'post3', -2), (u'post1', None)]
投稿のないものが最後に行くので、これには問題があります。djangoのSum
集計関数は、エントリなしの合計を0ではなくNoneとして受け取るため、これは、最初にすべての投稿に値0(またはredditのシステムのように値1)で投票した場合、Noneを取得できません。
for p in Post.objects.all():
Vote.objects.get_or_create(post_id=p.id, value=0)
その後、あなたは得るでしょう
>>> [(p.name, p.vote_total) for p in
Post.objects.annotate(vote_total=Sum('vote__value')).order_by('-vote_total')]
[(u'post2', 4), (u'post1', 0), (u'post4', -1), (u'post3', -2)]
編集:さまざまな投票タイプに関するコメントごとに、投票モデルにタイプを追加しました(上記で実行)。次のようなことができるはずです(「yourappname」をアプリケーションの名前に置き換えて、適切なデータベーステーブルを取得します)。
select_dict = dict(vote_total = "SELECT SUM(value) FROM yourappname_vote WHERE yourappname_vote.post_id = yourappname_post.id",
awesome_total = "SELECT SUM(value) FROM yourappname_vote WHERE yourappname_vote.post_id = yourappname_post.id AND yourappname_vote.type = 'AW' ",
useful_total = "SELECT SUM(value) FROM yourappname_vote WHERE yourappname_vote.post_id = yourappname_post.id AND yourappname_vote.type = 'US' ",)
posts = Post.objects.all().extra(select = select_dict).order_by('-vote_total')
>>> [(p.name, p.vote_total, p.awesome_total, p.useful_total) for p in posts]
[(u'post2', 4, 2, 2),
(u'post1', 0, 0, 0),
(u'post4', -1, -1, 0),
(u'post3', -2, -2, 0)]
これで、各投稿に、データベースへの1つのクエリがvote_total
含まれるようawesome_total
になります。useful_total
ORMよりも少し醜いですが、それでもかなり読みやすくなっています(これが、Sum集計の仕組みです)。順不同で表示されるNoneを通過するには、各カテゴリの投票に最初の投票を行う必要があります。
私はこれがうまくいくと思います:
Vote.objects.values_list('post', flat=True).order_by('value')
順序を逆にするには:
Vote.objects.values_list('post', flat=True).order_by('-value')
アップデート
postはForeignKey
toPost
なので、モデルが次のようになっていると仮定します。
class Post(models.Model):
post_id = models.AutoField(primary_key=True)
post_name = models.CharField(max_length=30, unique=True)
したがって、これは機能するはずです。名前が返されます。
Vote.objects.values_list('post__post_name', flat=True).order_by('value')
注_
リストを使用してクエリを実行し、エラーが表示される場合は、リストに変換するだけです。
list(Vote.objects.values_list('post__post_name', flat=True).order_by('value')))