2

1 人がメッセージを投稿し、他の数人がそれに返信するフォーラムを構築しています。

次のようなメッセージ モデルと応答モデルがあります。

class Messages (models.Model):
    author = models.ForeignKey(User)
    message = models.TextField()
    def __unicode__(self):
        return self.message

class Responses (models.Model):
    message = models.ForeignKey(Messages)
    responder = models.ForeignKey(User, related_name='responder')
    rsp_to = models.ForeignKey(User, related_name='rsp_to')
    rsp_from = models.ForeignKey(User, related_name='rsp_from')
    response = models.TextField()
    pub_date = models.DateTimeField('date_published')
    def __unicode__(self):
        return self.message

最新のレスポンダーからのすべての応答が最初になり、2 番目に新しいレスポンダーからの応答が 2 番目になるように、レスポンダーに従って編成されたクエリセットを取得したいと考えています。

db テーブルの例:

pk  message  responder  rsp_to  rsp_from  response  pub_date
------------------------------------------------------------
1    a        User.2  a.author   User.2    ....      1
2    a        User.3  a.author   User.3    ....      2
3    a        User.3  User.3    a.author   ....      3
4    a        User.4  a.author   User.4    ....      4
5    a        User.4  User.4    a.author   ....      5
6    a        User.2  User.2    a.author   ....      6
7    a        User.3  a.author   User.3    ....      7
8    a        User.3  User.3    a.author   ....      8
9    a        User.4  a.author   User.4    ....      9

並べ替えられたクエリセット:

pk  message  responder  rsp_to  rsp_from  response  pub_date
------------------------------------------------------------
9    a        User.4  a.author   User.4    ....      9
5    a        User.4   User.4   a.author   ....      5
4    a        User.4  a.author   User.4    ....      4
8    a        User.3   User.3   a.author   ....      8
7    a        User.3  a.author   User.3    ....      7
3    a        User.3   User.3   a.author   ....      3
2    a        User.3  a.author   User.3    ....      2
6    a        User.2   User.2   a.author   ....      6
1    a        User.2  a.author   User.2    ....      1

または、次のように表現します。

r = [<all responses from latest responder>, <all responses from 2nd latest responder>,..., <all responses from earliest responder>]

私が始めるなら:

r = Responses.objects.filter(message="a").order_by('-pub_date')

最初に最新の応答を取得します。その最新の一意のレスポンダからのすべての応答がクエリセットで最初にグループ化され、2 番目の一意のレスポンダからのすべての応答が 2 番目にグループ化されるように、クエリセットを並べ替えるにはどうすればよいですか?

4

1 に答える 1

0

sorted() の使用

sorted()まず、古き良き関数を使用して Python で並べ替えを行うことを考えてみましょう。これは一種の比較ソートです。つまり、アイテムをペアで比較し、一度に 1 ペアずつ並べ替えを行い、ペアごとにどちらが最初に来るかを決定します。比較並べ替えは、コンパレータ (並べ替えの引数として指定された関数) が合計順序を定義する場合にのみ機能します。

  1. a ≤ b かつ b ≤ a の場合、a = b (反対称、実際には比較ソートには必要ありません)。
  2. a ≤ b および b ≤ c の場合、a ≤ c (推移性);
  3. a ≤ b または b ≤ a (合計)。

したがって、テーブルから 2 つの行を取得し、どちらが最初に実行されるかを決定するコンパレータを定義でき、そのコンパレータが合計順序を定義できる場合は、sortedそのコンパレータを使用して呼び出すことができます。

しかし、そのようなコンパレータはあなたの問題には存在しません。2 人の異なるユーザーによる 2 つの行だけを考慮すると、どちらが最初に来るかわかりません。それらの著者による最新の投稿を常に知る必要があります。結論:使えないsorted()

SQL の使用

SQLがこれを処理できるかどうかはわかりません。あなたが持っているテーブルだけを使って、DjangoとPythonのものをすべて除外して質問を書き直してください。そのような質問を作成する場合は、この質問からその質問へのリンクを追加してください。SQL で処理できる場合は、 を呼び出すことができますResponses.objects.sql()

バケットの使用

以下のコードは、バケットを使用して希望どおりに並べ替える方法の例です。原則に焦点を当てるために、ダミー クラス Response を使用しました。

from random import randint, shuffle

# == Data definition ==
class Response:
  user = None #int
  time = None #int
  def __str__(self):
    return '(%d:%2d)' % (self.user,self.time)

# == Create random data ==
responses = []
for i in range(20):
  r = Response()
  r.user = randint(1,4)
  r.time = i
  responses.append(r)
shuffle(responses)

# == Put in buckets ==
bucketdict = {}
for r in responses:
  if r.user in bucketdict:
    bucketdict[r.user].append(r)
  else:
    bucketdict[r.user] = [r]

# == create list from dict ==
bucketlist = bucketdict.items()
def printbucketlist():
  for user,user_rsps in bucketlist:
    print user, 
    for rsp in user_rsps:
      print rsp,
    print
  print
printbucketlist()

# == Sort responses within each bucket ==
def rsp_comparator(r1,r2):
  return r2.time - r1.time
for user,responses in  bucketlist:
  responses.sort(rsp_comparator)
printbucketlist()

# == Sort bucketlist ==
def bucket_cmp(b1,b2):
  # assumes that the first response in the list has the highet time
  return b2[1][0].time - b1[1][0].time
bucketlist = sorted(bucketlist,cmp=bucket_cmp)
printbucketlist()

# == Concatenate into one list ==
sortedresponses = []
for user, user_rsps in bucketlist:
  for response in user_rsps:
    sortedresponses.append(response)
for response in sortedresponses:
  print response
于 2012-06-18T21:27:11.923 に答える