2009-08-06 27 views
13

Câu hỏi của tôi gần như giống hệt như this post, ngoại trừ việc tôi đang sử dụng Python và Django thay vì PHP.Các ngày lập nhóm ở Django

Nhiệm vụ là thực hiện:

id date 
1 2009-01-01 10:15:23 
2 2009-01-01 13:21:29 
3 2009-01-02 01:03:13 
4 2009-01-03 12:20:19 
5 2009-01-03 13:01:06 

Và đầu ra:

2009-01-01 
1 
2 
2009-01-02 
3 
2009-01-03 
4 
5 

Tôi có thể tự hack cái gì với nhau bằng Looping qua ngày được sắp xếp và xuất HTML thành một chuỗi trong tập tin xem python của tôi , nhưng tôi tự hỏi: là có một cách tốt hơn bằng cách sử dụng một mẫu Django hoặc một tính năng tiện lợi Python?

Trả lời

30

Bạn có thể giải quyết vấn đề này với nhóm lạingày templatetags.

{% regroup object_list by start_date|date:"Y-m-d" as objects_by_day %} 
{% for d in objects_by_day %} 
### DO SOMETHING HERE 
{% endfor %} 
+0

Tôi đã được hầu hết các cách có nhưng không nhận ra bạn có thể kết hợp trong bộ lọc ngày. Rất cám ơn vì điều này! Chính xác những gì tôi đang tìm kiếm. – saturdayplace

+0

Thiên Chúa tốt, làm thế nào tôi không biết về điều này –

+0

nó nhanh hơn để sử dụng start_date.date nếu bạn cần 'phần ngày' –

2

Điều này sẽ dễ dàng hơn nếu bạn sử dụng các hàm định dạng ngày của cơ sở dữ liệu để loại bỏ các lần (trong lựa chọn). Sau đó, bạn có thể nhóm theo cột được định dạng (sử dụng bí danh cột).

Sau đó, bạn có thể sử dụng vòng lặp có logic nhỏ để chuyển đổi kết quả đến những gì bạn muốn. Tôi đã không được sử dụng hệ thống mẫu django của bài viết nào, nhưng đây là những gì logic sẽ trông như thế bằng Python:

>>> rows = [(1,'2009-01-01'), (2,'2009-01-01'), (3, '2009-02-02'), \ 
(4, '2009-02-02'), (5, '2009-02-02')] 
>>> topdate = None 
>>> for r in rows: 
...  if topdate <> r[1]: 
...    topdate = r[1] 
...    print r[1] 
...  print r[0] 
... 
2009-01-01 
1 
2 
2009-02-02 
3 
4 
5 

Nên có một cách thẳng về phía trước để chuyển đổi này để django mẫu mã.

+0

Tôi có thể nhóm dữ liệu, nhưng "logic nhỏ" bên trong hệ thống khuôn mẫu sẽ như thế nào? – ine

+0

Tôi đã thêm một ví dụ. –

+0

Tôi không thuyết phục bạn có thể làm điều này trong các mẫu Django. Ngay cả khi bạn có thể, bạn sẽ không muốn. Tốt hơn là làm điều đó trong: (1) mã xem hoặc (2) một templatetag nơi bạn có thể sử dụng python thực. – hughdbrown

15

itertools.groupby là thân yêu, thân yêu bạn bè của bạn:

import itertools 

dates = [ 
    (1,'2009-01-01 10:15:23'), 
    (2,'2009-01-01 13:21:29'), 
    (3,'2009-01-02 01:03:13'), 
    (4,'2009-01-03 12:20:19'), 
    (5,'2009-01-03 13:01:06'), 
] 

for key,group in itertools.groupby(dates, key=lambda x: x[1][:11]): 
    print key 
    for element in group: 
     print ' ', element 

Đoạn mã trên sẽ in như sau:

2009-01-01 
    (1, '2009-01-01 10:15:23') 
    (2, '2009-01-01 13:21:29') 
2009-01-02 
    (3, '2009-01-02 01:03:13') 
2009-01-03 
    (4, '2009-01-03 12:20:19') 
    (5, '2009-01-03 13:01:06') 
+0

Tuyệt vời! itertools.groupby chỉ là những gì tôi đang tìm kiếm. – ine

+0

Nếu bạn định làm như thế này, bạn cần một cái gì đó như thế này: "def sidebar_date_list(): từ nhóm nhập itertoolsby data = [datetime.date (post.created_at.year, post.created_at.month , 1) cho bài đăng trong Post.objects.filter (xuất bản = 1) .order_by ('- created_at')] trả về {'tháng': [k cho k, _ trong nhómby (dữ liệu)]} Lưu ý rằng SQL phải được sắp xếp cho groupby() để sử dụng. " Được nâng từ đây: http://www.djangrrl.com/view/using-python-str-datetime-lists-and-sets-to-group-dates/ – hughdbrown

+0

Hoặc như thế này nếu bạn muốn nhóm theo ngày: " def sidebar_date_list(): \t từ nhóm nhập itertoolsby \t data = [datetime.date (post.created_at.year, post.created_at.month, post.created_at.day) cho bài đăng trong Post.objects.filter (publish = 1) .order_by ('- created_at')] \t return {'days': [k cho k, _ in groupby (data)]} " – hughdbrown

8

Đây là tất cả câu trả lời hợp lý nếu OP có thể sử dụng python trong mẫu mã. (Và trên tài khoản đó, tôi sẽ ưu tiên giải pháp itertools.groupby().) Nhưng bạn không thể sử dụng python trong mã mẫu. Trong trường hợp tốt nhất, bạn sẽ viết một templatetag thực hiện thao tác này. Và đã có một templatetag thực hiện điều này.

Để làm các nhóm trong Django bên trong mẫu, sử dụng tập hợp lại:

{% regroup people by gender as gender_list %} 

<ul> 
{% for gender in gender_list %} 
    <li>{{ gender.grouper }} 
    <ul> 
     {% for item in gender.list %} 
     <li>{{ item.first_name }} {{ item.last_name }}</li> 
     {% endfor %} 
    </ul> 
    </li> 
{% endfor %} 
</ul> 

Ví dụ nâng lên từ Django regroup documentation. regroup có sẵn ở django 0.96, 1.0 và ít nhất là 1.1.

Nếu bạn cho tôi ý tưởng về những gì được chuyển đến mẫu, tôi có thể hack một ví dụ sử dụng dữ liệu của bạn.

Ngoài ra, còn có blog post trong đó DjangoGrrl hoạt động thông qua chính xác câu hỏi này.

+0

Các ngôn ngữ ứng khẩu có xu hướng cung cấp đủ các cấu trúc ngôn ngữ giống nhau mà bạn có thể chuyển đổi giữa hai cấu trúc này một cách dễ dàng (chúng có chung một bytecode đích). –

+0

Không được thô lỗ, nhưng bạn có lập trình ở Django không? Đối với mục đích thực tế, chỉ có các so sánh thô sơ và các hoạt động chuyển nhượng. Kiểm tra những gì có sẵn mà không cần sử dụng templatetags: http://docs.djangoproject.com/en/dev/topics/templates/ – hughdbrown

+0

Thật không may, tôi đang sử dụng 0,96 nhưng đây là một tài nguyên tuyệt vời cho những người trên 1.0 hoặc cao hơn! – ine

9

Khi thực hiện báo cáo trên tập dữ liệu lớn hơn itertools.group_by có thể quá chậm. Trong những trường hợp đó, tôi làm cho bưu cục xử lý nhóm:

truncate_date = connection.ops.date_trunc_sql('day','timestamp') 
qs = qs.extra({'date':truncate_date}) 
return qs.values('date').annotate(Sum('amount')).order_by('date') 
Các vấn đề liên quan