Rya*_*yan 6 django django-orm django-filter
我有一个看起来像这样的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)
Run Code Online (Sandbox Code Playgroud)
对于每个Response对象,有两个编码对象,其中qid ="risk",一个用于编码器3,一个用于编码器4.我希望能够做的是获取所有Response对象的列表,其值不同编码器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
Run Code Online (Sandbox Code Playgroud)
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')]
Run Code Online (Sandbox Code Playgroud)
当您连接到查询中已有的表时,ORM 将为第二个表分配一个别名,在本例中为 T3,您可以在 的参数中使用它extra()。要找出别名是什么,您可以进入 shell 并print qset.query.
更新: 看来您实际上不必使用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')]
Run Code Online (Sandbox Code Playgroud)
请参阅有关Q 对象的 Django 文档
顺便说一句,如果您想要两个 Coding 实例,那么这里会遇到 N + 1 查询问题,因为 djangoselect_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...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2696 次 |
| 最近记录: |