2013-05-11 130 views
6

我有一个Django的模型,看起来像这样的价值观: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 =“风险”两种编码对象,一个编码器3和一个对于编码器4.我希望能够做的是得到编码器3和编码器4之间的差值大于1的所有Response对象的列表。值字段存储编号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 
+1

我想你的意思是包括'c1.response_id = c2.response_id'您的查询的WHERE子句。 – 2013-05-11 22:56:25

+0

@AryehLeibTaurog是的,我做到了。谢谢。 – Ryan 2013-05-11 23:40:07

回答

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将为第二个别名分配一个别名,在这种情况下,T3可以用于参数extra()。要查明别名是什么,可以将其放入shell并print qset.query

F objects

见Django文档和extra

更新:看来你居然没有使用extra(),或找出别名Django使用,因为每次你指的是你的查找response__coding, django将使用最初创建的别名。下面就来看看在两个方向的差异的一种方式:

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')] 

见Django文档上Q objects

顺便说一句,如果你会想这两个编码的情况下,你在这里有N + 1个查询问题,因为django的select_related()不会得到反向的FK关系。但是由于您已经有了查询中的数据,您可以使用上述的T3别名和extra(select={'other_value':'T3.value'})来检索所需的信息。来自相应编码记录的value数据将作为检索的编码实例上的属性被访问,即,作为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... 
+0

这太好了。无论编码器3或编码器4是否更高,是否有办法让它工作? – Ryan 2013-05-12 00:02:58

+2

我用适用于两种情况的解决方案更新了答案。 – 2013-05-12 13:46:15