2013-05-11 38 views
6

Tôi có một mô hình Django mà trông giống như sau:Django so sánh giá trị của hai đối tượng

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) 

Đối với mỗi đối tượng Response, có hai đối tượng mã hóa với qid = "nguy cơ", một cho coder 3 và một cho coder 4. Điều tôi muốn làm là lấy danh sách tất cả các đối tượng Response mà sự khác biệt về giá trị giữa coder 3 và coder 4 lớn hơn 1. Trường giá trị lưu trữ số 1-7.

Tôi nhận thấy rằng việc thiết lập giá trị dưới dạng CharField có thể là một sai lầm, nhưng hy vọng tôi có thể làm được điều đó.

Tôi tin rằng một cái gì đó giống như SQL sau đây sẽ làm những gì tôi đang tìm kiếm, nhưng tôi thà làm điều này với 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

Tôi nghĩ bạn định gửi cho 'c1.response_id = c2.response_id' trong mệnh đề WHERE của truy vấn của bạn. –

+0

@AryehLeibTaurog vâng tôi đã làm. Cảm ơn. – Ryan

Trả lời

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

Khi bạn tham gia vào một bảng đã có trong truy vấn , ORM sẽ gán bí danh thứ hai là một bí danh, trong trường hợp này là T3, bạn có thể sử dụng nó trong các tham số cho extra(). Để tìm ra bí danh nào bạn có thể thả vào vỏ và print qset.query.

tài liệu

Xem Django trên F objectsextra

Cập nhật: Có vẻ như bạn thực sự không cần phải sử dụng extra(), hoặc tìm ra những gì bí danh django sử dụng, bởi vì mỗi khi bạn đề cập đến response__coding trong tra cứu của bạn, django sẽ sử dụng bí danh được tạo ban đầu. Dưới đây là một cách để tìm kiếm sự khác biệt trong hai hướng:

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

Xem Django tài liệu về Q objects

BTW, Nếu bạn đang muốn cả hai trường hợp có mã, bạn có một N + 1 thắc mắc vấn đề ở đây, bởi vì django's select_related() sẽ không nhận được các mối quan hệ ngược lại FK. Nhưng vì bạn đã có dữ liệu trong truy vấn, bạn có thể truy xuất thông tin được yêu cầu bằng cách sử dụng bí danh T3 như được mô tả ở trên và extra(select={'other_value':'T3.value'}). Dữ liệu value từ bản ghi Mã hóa tương ứng sẽ có thể truy cập dưới dạng thuộc tính trên phiên bản Mã hóa đã truy xuất, tức là c.other_value.

Ngẫu nhiên, câu hỏi của bạn là đủ chung, nhưng có vẻ như bạn có một lược đồ thuộc tính-giá trị thuộc tính, trong một kịch bản RDB thường được coi là một mẫu chống. Bạn có thể được tốt hơn off dài hạn (và truy vấn này sẽ đơn giản hơn) với một trường risk:

class Coding(models.Model): 
    response = models.ForeignKey(Response) 
    coder = models.ForeignKey(User) 
    risk = models.IntegerField() 
    # other fields for other qid 'attribute' names... 
+0

Điều này thật tuyệt. Có cách nào để làm cho nó hoạt động bất kể coder 3 hay coder 4 có cao hơn không? – Ryan

+2

Tôi đã cập nhật câu trả lời bằng giải pháp phù hợp cho cả hai trường hợp. –

Các vấn đề liên quan