1

私は Django ORM の新しい集約機能をいじっていましたが、可能だと思われるクラスの問題がありますが、それを機能させることができないようです。生成しようとしているクエリのタイプについては、こちらで説明しています。

だから、私は次のモデルを持っているとしましょう -

class ContactGroup(models.Model):
    .... whatever ....

class Contact(models.Model):
    group = models.ForeignKey(ContactGroup)
    name = models.CharField(max_length=20)
    email = models.EmailField()
...

class Record(models.Model):
    contact = models.ForeignKey(Contact)
    group = models.ForeignKey(ContactGroup)
    record_date = models.DateTimeField(default=datetime.datetime.now)

    ... name, email, and other fields that are in Contact ...

そのため、連絡先が作成または変更されるたびに、その時点で連絡先に表示されている情報をタイムスタンプと共に保存する新しいレコードが作成されます。ここで、たとえば、ContactGroup に関連付けられたすべての Contact の最新の Record インスタンスを返すクエリが必要です。擬似コード:

group = ContactGroup.objects.get(...)
records_i_want = group.record_set.most_recent_record_for_every_contact()

filter(record_date__lt=some_date)これを理解したら、クエリセットに をスローして、 に存在する情報を取得できるようにしたいだけですsome_date

誰にもアイデアはありますか?

編集:私は本当に自分自身を明確にしていないようです. このようなモデルを使用して、純粋な django ORM (extra() なし) で次のことを行う方法が必要です。

ContactGroup.record_set.extra(where=["history_date = (select max(history_date) from app_record r where r.id=app_record.id and r.history_date <= '2009-07-18')"])

where 句にサブクエリを配置することは、この問題を解決するための 1 つの戦略にすぎません。他の問題は、上記の最初のリンクで十分にカバーされています。extra() を使用しないと where 句のサブセレクトができないことはわかっていますが、おそらく他の方法の 1 つが新しい集計機能によって可能になったと思いました。

4

2 に答える 2

0

Djangoのオブジェクトへの変更の記録を保持したいようです。

Pro Djangoには、第11章(アプリケーションの拡張)のセクションがあり、作成者は、挿入/削除/更新を追跡するクライアントとして別のモデルを使用するモデルを作成する方法を示しています。モデルは、クライアント定義から動的に生成され、依存します。信号で。コードはmost_recent()関数を示していますが、これを適応させて特定の日付のオブジェクトの状態を取得することもできます。

問題があるのはDjangoでの追跡であり、これを取得するためのSQLではないと思います。

于 2009-07-21T21:46:18.837 に答える
0

まず、次のことを指摘しておきます。

ContactGroup.record_set.extra(where=["history_date = (select max(history_date) from app_record r where r.id=app_record.id and r.history_date <= '2009-07-18')"])

次と同じ効果は得られません。

records_i_want = group.record_set.most_recent_record_for_every_contact()

最初のクエリは、extra で指定された日時よりも前の record_date を持つ、特定のグループに関連付けられた (または特定のグループのいずれかの連絡先に関連付けられた) すべてのレコードを返します。シェルでこれを実行してから、これを実行して、作成された django クエリを確認します。

from django.db import connection
connection.queries[-1]

それは明らかにします:

'SELECT "contacts_record"."id", "contacts_record"."contact_id", "contacts_record"."group_id", "contacts_record"."record_date", "contacts_record"."name", "contacts_record"."email" FROM "contacts_record" WHERE "contacts_record"."group_id" = 1  AND record_date = (select max(record_date) from contacts_record r where r.id=contacts_record.id and r.record_date <= \'2009-07-18\')

まさにあなたが望むものではありませんよね?

集約機能は、集約データに関連付けられたオブジェクトではなく、集約データを取得するために使用されるようになりました。したがって、 group.record_set.most_recent_record_for_every_contact()を取得しようとするときに集計を使用して実行されるクエリの数を最小限に抑えようとすると、成功しません。

集計を使用しない場合、次を使用して、グループに関連付けられたすべての連絡先の最新のレコードを取得できます。

[x.record_set.all().order_by('-record_date')[0] for x in group.contact_set.all()]

集計を使用して、私がそれに到達できる最も近いものは次のとおりです。

group.record_set.values('contact').annotate(latest_date=Max('record_date'))

後者は、次のような辞書のリストを返します。

[{'contact': 1, 'latest_date': somedate }, {'contact': 2, 'latest_date': somedate }]

したがって、特定のグループの連絡先ごとに 1 つのエントリと、それに関連付けられている最新の記録日です。

とにかく、クエリの最小数は、おそらく 1 + グループ内の連絡先の数です。単一のクエリを使用して結果を取得することに興味がある場合は、それも可能ですが、別の方法でモデルを構築する必要があります。しかし、それはあなたの問題のまったく別の側面です。

これが、集計/通常の ORM 関数を使用して問題にアプローチする方法を理解するのに役立つことを願っています。

于 2009-07-24T20:49:53.283 に答える