2013-02-12 17 views
10

Tôi cần điền vào mẫu có bản tóm tắt hoạt động của người dùng trong một hệ thống nhắn tin đơn giản. Đối với mỗi người gửi thư, tôi muốn số lượng thư được gửi và số người nhận riêng biệt.Phiên bản Django ORM của SQL COUNT (DISTINCT <column>)

Dưới đây là một phiên bản đơn giản của mô hình:

class Message(models.Model): 
    sender = models.ForeignKey(User, related_name='messages_from') 
    recipient = models.ForeignKey(User, related_name='messages_to') 
    timestamp = models.DateTimeField(auto_now_add=True) 

Đây là cách tôi muốn làm điều đó trong SQL:

SELECT sender_id, COUNT(id), COUNT(DISTINCT recipient_id) 
    FROM myapp_messages 
    GROUP BY sender_id; 

Tôi đã đọc qua tài liệu về tập hợp trong các truy vấn ORM, và mặc dù chú thích() có thể xử lý cột COUNT đầu tiên, nhưng tôi không thấy cách nào để có được kết quả COUNT (DISTINCT) (thậm chí thêm (select = {}) đã không hoạt động, mặc dù có vẻ như nó cần). Điều này có thể được dịch sang một truy vấn ORM Django hay tôi chỉ nên gắn bó với SQL thô?

+0

Các [ ' .distinct() '] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.distinct) bộ lọc có thể com e tiện dụng. –

+0

Nếu chúng ta bỏ qua COUNT (DISTINCT recipient_id), nó khá đơn giản khi sử dụng chức năng chú thích và đếm. Ở đây, Django của riêng biệt() không giúp đỡ. Tôi không nghĩ rằng có thể tích hợp hai thứ này (chú thích và phân biệt) với nhau. Bạn phải viết hai truy vấn tôi đoán. – jurgenreza

Trả lời

8

Bạn thực sự có thể sử dụng riêng biệt và đếm với nhau, như đã thấy trên câu trả lời này: https://stackoverflow.com/a/13145407/237091

Trong trường hợp của bạn:

SELECT sender_id, COUNT(id), COUNT(DISTINCT recipient_id) 
FROM myapp_messages 
GROUP BY sender_id; 

sẽ trở thành:

Message.objects.values('sender').annotate(
    message_count=Count('sender'), 
    recipient_count=Count('recipient', distinct=True)) 
4
from django.db.models import Count 

messages = Message.objects.values('sender').annotate(message_count=Count('sender')) 

for m in messages: 
    m['recipient_count'] = len(Message.objects.filter(sender=m['sender']).\ 
           values_list('recipient', flat=True).distinct()) 
+0

Cảm ơn bạn! Tôi có đúng trong sự hiểu biết rằng điều này có nghĩa rằng sẽ có nhiều truy vấn cơ sở dữ liệu như có người gửi tin nhắn (cộng một)? – nephtes

+0

@nephtes Có. Về cơ bản tôi không nghĩ rằng có bất kỳ cách nào để sử dụng khác biệt() bên trong Count(). Có lẽ, bạn tốt hơn với sql thô. Tôi nghĩ rằng đây là cách tốt nhất để làm điều đó với django, trừ khi những người khác đưa ra một ý tưởng tốt hơn! – jurgenreza

+1

@jurgenreza (Tôi biết bài viết này là cũ nhưng ...) Tôi tin rằng một cách tốt hơn sẽ được sử dụng thêm: Message.objects.filter (...). Thêm ({'recipient_count': 'COUNT (DISTINCT recipient_id) '}). giá trị (' recipient_count '). Tài liệu trên thêm: https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.extra – paperreduction

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