7

次のような Django モデルがあります。

class Response(models.Model):
    transcript = models.TextField(null=True)

class Coding(models.Model):
    qid = models.CharField(max_length = 30)
    value = models.CharField(max_length = 200)
    response = models.ForeignKey(Response)
    coder = models.ForeignKey(User)

Response オブジェクトごとに、qid = "risk" の 2 つのコーディング オブジェクトがあり、1 つはコーダー 3 用、もう 1 つはコーダー 4 用です。コーダ 3 とコーダ 4 の間の値は 1 より大きくなります。値フィールドには 1 ~ 7 の数値が格納されます。

後から考えると、値を CharField として設定するのは間違いだったかもしれませんが、それを回避できることを願っています。

次のSQLのようなものが私が探していることを行うと信じていますが、ORMでこれを行いたいです

SELECT UNIQUE c1.response_id FROM coding c1, coding c2
WHERE c1.coder_id = 3 AND 
      c2.coder_id = 4 AND
      c1.qid = "risk" AND 
      c2.qid = "risk" AND
      c1.response_id = c2.response_id AND
      c1.value - c2.value > 1
4

1 に答える 1

2
from django.db.models import F
qset = Coding.objects.filter(response__coding__value__gt=F('value') + 1,
                             qid='risk',  coder=4
                    ).extra(where=['T3.qid = %s', 'T3.coder_id = %s'],
                            params=['risk', 3])
responses = [c.response for c in qset.select_related('response')]

クエリに既に含まれているテーブルに結合すると、ORM は 2 番目のテーブルにエイリアス (この場合は T3) を割り当てます。これは、 のパラメータで使用できますextra()。エイリアスが何であるかを調べるには、シェルにドロップしてprint qset.query.

Fオブジェクト追加のDjangoドキュメントを参照してください

更新:extra()ルックアップで参照するたびにresponse__coding、django は最初に作成されたエイリアスを使用するため、 実際には を使用したり、django が使用するエイリアスを把握したりする必要はないようです。どちらの方向でも違いを探す方法の 1 つを次に示します。

from django.db.models import Q, F
gt = Q(response__coding__value__gt=F('value') + 1)
lt = Q(response__coding__value__lt=F('value') - 1)
match = Q(response__coding__qid='risk', response__coding__coder=4)
qset = Coding.objects.filter(match & (gt | lt), qid='risk', coder=3)
responses = [c.response for c in qset.select_related('response')]

Q オブジェクトに関する Django のドキュメントを参照してください。

ところで、両方の Coding インスタンスが必要な場合は、djangoselect_related()が逆 FK 関係を取得しないため、ここで N + 1 クエリの問題が発生します。ただし、クエリには既にデータがあるため、上記のように T3 エイリアスを使用して必要な情報を取得できますextra(select={'other_value':'T3.value'})。対応する Coding レコードのvalueデータは、取得した Coding インスタンスの属性として、つまり としてアクセスできますc.other_value

ちなみに、あなたの質問は十分に一般的ですが、RDBシナリオでは一般的にアンチパターンと見なされるエンティティ属性値スキーマがあるようです。フィールドを使用すると、長期的に(このクエリはより簡単になります)の方が良い場合がありriskます。

class Coding(models.Model):
    response = models.ForeignKey(Response)
    coder = models.ForeignKey(User)
    risk = models.IntegerField()
    # other fields for other qid 'attribute' names...
于 2013-05-11T22:30:05.240 に答える