2013-05-30 37 views
6

Tôi có ứng dụng django đang thực hiện một số lần ghi nhật ký. Mô hình của tôi trông giống như sau:Tổng số bản ghi Django mỗi ngày

class MessageLog(models.Model): 
    logtime = models.DateTimeField(auto_now_add=True) 
    user = models.CharField(max_length=50) 
    message = models.CharField(max_length=512) 

Điều muốn làm là nhận được số lượng thư trung bình được ghi lại mỗi ngày trong tuần để tôi có thể xem ngày nào hoạt động nhiều nhất. Tôi đã quản lý để viết truy vấn kéo tổng số thư mỗi ngày là:

for i in range(1, 8): 
    MessageLog.objects.filter(logtime__week_day=i).count() 

Nhưng tôi đang gặp khó khăn khi tính trung bình trong truy vấn. Những gì tôi có ngay bây giờ là:

for i in range(1, 8): 
    MessageLog.objects.filter(logtime__week_day=i).annotate(num_msgs=Count('id')).aggregate(Avg('num_msgs')) 

Vì lý do nào đó, điều này sẽ trở lại 1.0 cho mỗi ngày. Tôi nhìn vào SQL nó được tạo ra và nó là:

SELECT AVG(num_msgs) FROM (
SELECT 
`myapp_messagelog`.`id` AS `id`, `myapp_messagelog`.`logtime` AS `logtime`, 
`myapp_messagelog`.`user` AS `user`, `myapp_messagelog`.`message` AS `message`, 
COUNT(`myapp_messagelog`.`id`) AS `num_msgs` 
FROM `myapp_messagelog` 
WHERE DAYOFWEEK(`myapp_messagelog`.`logtime`) = 1 
GROUP BY `myapp_messagelog`.`id` ORDER BY NULL 
) subquery 

Tôi nghĩ rằng vấn đề có thể đến từ id GROUP BY nhưng tôi không thực sự chắc chắn. Ai có ý tưởng hay gợi ý nào không? Cảm ơn trước!

Trả lời

9

Lý do truy vấn được liệt kê của bạn luôn cho 1 là vì bạn không nhóm theo ngày. Về cơ bản, bạn đã yêu cầu cơ sở dữ liệu lấy các hàng MessageLog rơi vào một ngày nhất định trong tuần. Đối với mỗi hàng như vậy, hãy đếm số lượng id mà nó có (luôn luôn là 1). Sau đó, tính trung bình của tất cả các số đó, tất nhiên cũng là 1.

Thông thường, bạn cần sử dụng mệnh đề values để nhóm các hàng MessageLog trước các chi tiết annotateaggregate của mình. Tuy nhiên, vì trường logtime của bạn là ngày giờ thay vì chỉ là một ngày, tôi không chắc chắn bạn có thể thể hiện trực tiếp với ORM của Django. Bạn chắc chắn có thể làm điều đó với mệnh đề extra, như được hiển thị here. Hoặc nếu bạn cảm thấy thích nó, bạn có thể khai báo một khung nhìn trong SQL của bạn với nhiều phép tính tổng hợp và trung bình như bạn thích và khai báo một mô hình không được quản lý cho nó, sau đó chỉ cần sử dụng ORM bình thường.

Vì vậy, trường extra hoạt động để nhận tổng số bản ghi mỗi ngày thực tế, nhưng không xử lý tổng hợp trung bình của chú thích được tính toán. Tôi nghĩ rằng điều này có thể được tóm tắt đầy đủ từ mô hình mà bạn phải sử dụng truy vấn SQL thô hoặc ít nhất tôi không thể tìm thấy bất kỳ thứ gì làm cho nó hoạt động trong một cuộc gọi.

Điều đó nói rằng, bạn đã biết cách bạn có thể nhận tổng số bản ghi mỗi ngày trong tuần trong một truy vấn đơn giản như được hiển thị trong câu hỏi của bạn.

Và truy vấn này sẽ cho bạn biết có bao nhiêu hồ sơ ngày riêng biệt có đang ở trên một tuần đưa ra:

MessageLog.objects.filter(logtime__week_day=i).dates('logtime', day').count() 

Vì vậy, bạn có thể làm phép tính trung bình trong Python thay vào đó, mà có thể được đơn giản hơn là cố gắng có được quyền SQL .

Cách khác, truy vấn này sẽ giúp bạn có được số liệu của các thông điệp cho tất cả các ngày trong tuần trong một truy vấn hơn là một vòng lặp for:

MessageLog.objects.extra({'weekday': "dayofweek(logtime)"}).values('weekday').annotate(Count('id')) 

Nhưng tôi đã không thể có được một truy vấn tốt đẹp để cung cấp cho bạn số ngày riêng biệt cho mỗi ngày trong tuần được chú thích cho các truy vấn ngày tháng đó mất khả năng xử lý cuộc gọi chú thích và chú thích trên giá trị extra dường như không hoạt động.

Điều này đã gây ngạc nhiên một cách đáng ngạc nhiên, vì không phải là biểu thức SQL khó.

+0

Cảm ơn bạn đã giải thích! Điều đó làm cho rất nhiều ý nghĩa. Tôi đã thử sử dụng mệnh đề bổ sung, tuy nhiên bây giờ tôi nhận được một lỗi SQL. Tôi đã sửa đổi truy vấn của mình thành: MessageLog.objects.filter (logtime__week_day = i) .extra ({'date_logged': "date (logtime)"}). Giá trị ('date_logged') .annotate (num_msgs = Count ('id')) .trung bình (Trung bình ('num_msgs')) Và lỗi tôi nhận được là "Bạn có lỗi trong cú pháp SQL của mình; hãy kiểm tra hướng dẫn tương ứng với phiên bản máy chủ MySQL của bạn để biết cú pháp đúng sử dụng gần 'FROM (SELECT (ngày (logtime)) AS 'date_logged', COUNT (' myapp_messagelog'.'id' tại dòng 1 ") – bb89

+0

Vâng, điều đó không hoàn toàn hoạt động, phải không? Điều khoản tổng hợp ném nó đi - nó Bạn có thể nhận được tổng số lượng tin nhắn trong một vài ngày trong tuần theo nhiều cách khác nhau, nhưng tôi không thể tìm ra cách để làm cho ORM của Django thực hiện điều này trong một cuộc gọi. những gì tôi đã đưa ra wit h vào câu trả lời của tôi. –

+0

Tôi thực sự đã kết thúc việc tạo ra một khung nhìn (thực sự cần 2 cho mysql) và sau đó là một mô hình không được quản lý như bạn đã đề xuất và nó hoạt động hoàn hảo. Tôi sẽ thêm một bài đăng khác giải thích những gì tôi đã làm sau đó cho những người có thể quan tâm. Cảm ơn một lần nữa vì tất cả sự giúp đỡ của bạn! – bb89

2

Tôi làm điều gì đó tương tự với trường ngày giờ, nhưng chú thích trên các giá trị bổ sung không hoạt động đối với tôi. Tôi có một mô hình Record với một lĩnh vực datetime "created_at" và một lĩnh vực "my_value" tôi muốn có được mức trung bình cho.

from django.db.models import Avg 

qs = Record.objects.extra({'created_day':"date(created_at)"}).\ 
    values('created_day').\ 
    annotate(count=Avg('my_value) 

Phía trên sẽ nhóm theo ngày giá trị datetime trong trường "created_at".

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