Sắp xếp các mục có liên quan trong một mẫu Django


87

Có thể sắp xếp một tập hợp các mục liên quan trong một mẫu DJango không?

Đó là: mã này (với các thẻ HTML bị bỏ qua để rõ ràng):

{% for event in eventsCollection %}
   {{ event.location }}
   {% for attendee in event.attendee_set.all %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

hiển thị gần như chính xác mà tôi muốn. Điều duy nhất tôi muốn thay đổi là danh sách những người tham dự được sắp xếp theo họ. Tôi đã thử nói điều gì đó như thế này:

{% for event in events %}
   {{ event.location }}
   {% for attendee in event.attendee_set.order_by__last_name %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

Than ôi, cú pháp trên không hoạt động (nó tạo ra một danh sách trống) và cũng không có bất kỳ biến thể nào khác mà tôi đã nghĩ đến (rất nhiều lỗi cú pháp được báo cáo, nhưng không có gì đáng mừng).

Tất nhiên, tôi có thể tạo ra một số loại danh sách người tham dự được sắp xếp theo quan điểm của tôi, nhưng đó là một giải pháp xấu xí và mỏng manh (và tôi đã đề cập đến việc xấu xí).

Không cần phải nói, nhưng tôi sẽ nói điều đó, tôi đã xem xét các tài liệu trực tuyến và tìm kiếm Stack Overflow và các kho lưu trữ của django-user mà không tìm thấy bất kỳ điều gì hữu ích (à, nếu chỉ một bộ truy vấn là một từ điển dictsort sẽ làm được công việc, nhưng nó không phải và nó không)

==============================================

Đã chỉnh sửa để bổ sung thêm suy nghĩ sau khi chấp nhận câu trả lời của Tawmas.


Tawmas đã giải quyết vấn đề chính xác như tôi đã trình bày - mặc dù giải pháp không như tôi mong đợi. Kết quả là tôi đã học được một kỹ thuật hữu ích có thể được sử dụng trong các tình huống khác.

Câu trả lời của Tom đề xuất một cách tiếp cận mà tôi đã đề cập trong OP của mình và bị bác bỏ một cách ngập ngừng là "xấu xí".

"Xấu xí" là một phản ứng ruột, và tôi muốn làm rõ điều gì sai với nó. Khi làm như vậy, tôi nhận ra rằng lý do khiến nó là một cách tiếp cận xấu xí là vì tôi đã chán nản với ý tưởng truyền một tập hợp truy vấn tới mẫu sẽ được hiển thị. Nếu tôi nới lỏng yêu cầu đó, thì sẽ có một cách tiếp cận đơn giản mà hiệu quả.

Tôi chưa thử điều này, nhưng giả sử rằng thay vì chuyển bộ truy vấn, mã chế độ xem được lặp lại qua bộ truy vấn tạo ra danh sách Sự kiện, sau đó trang trí mỗi Sự kiện bằng một bộ truy vấn cho những người tham dự tương ứng mà WAS đã sắp xếp (hoặc lọc, hoặc bất cứ điều gì) theo cách mong muốn. Một cái gì đó như vậy:

eventCollection = []   
events = Event.object.[filtered and sorted to taste]
for event in events:
   event.attendee_list = event.attendee_set.[filtered and sorted to taste]
   eventCollection.append(event)

Bây giờ mẫu trở thành:

{% for event in events %}
   {{ event.location }}
   {% for attendee in event.attendee_list %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

Nhược điểm là chế độ xem phải "hiện thực hóa" tất cả các sự kiện cùng một lúc, điều này có thể là một vấn đề nếu có số lượng lớn các sự kiện. Tất nhiên người ta có thể thêm phân trang, nhưng điều đó làm phức tạp chế độ xem đáng kể.

Mặt thuận lợi là mã "chuẩn bị dữ liệu để được hiển thị" trong chế độ xem nơi nó thuộc về cho phép mẫu tập trung vào việc định dạng dữ liệu được cung cấp bởi chế độ xem để hiển thị. Điều này là đúng và thích hợp.

Vì vậy, kế hoạch của tôi là sử dụng kỹ thuật của Tawmas cho các bảng lớn và kỹ thuật trên cho các bảng nhỏ, với định nghĩa trái lớn và nhỏ cho người đọc (cười toe toét).

Câu trả lời:


135

Bạn cần chỉ định thứ tự trong mô hình người tham dự, như thế này. Ví dụ: (giả sử lớp người mẫu của bạn có tên là Người tham dự):

class Attendee(models.Model):
    class Meta:
        ordering = ['last_name']

Xem hướng dẫn sử dụng để tham khảo thêm.

CHỈNH SỬA . Một giải pháp khác là thêm thuộc tính vào mô hình Sự kiện của bạn, mà bạn có thể truy cập từ mẫu của mình:

class Event(models.Model):
# ...
@property
def sorted_attendee_set(self):
    return self.attendee_set.order_by('last_name')

Bạn có thể xác định thêm những thứ này khi bạn cần ...


Cảm ơn nhận xét của bạn, nhưng điều này chỉ hoạt động nếu tôi muốn đặt thứ tự hiển thị trở thành tài sản vĩnh viễn của người tham dự, điều này tôi không làm được. Ví dụ, tôi có thể muốn hiển thị những người tham dự được sắp xếp theo ngày nhận đăng ký của họ, vì vậy tôi sẽ biết những người tham dự nào sẽ được thông báo rằng không còn chỗ cho họ.
Dale Wilson

Tôi đã thêm một giải pháp thay thế cho bạn. Nó sẽ cho phép bạn sự linh hoạt mà bạn cần.
tawmas

@Mark Thật vậy. Theo như tôi hiểu @propertylà quá mức cần thiết ở đây vì không có người thu tiền hoặc người thiết lập nào liên quan: stackoverflow.com/questions/1554546/…
Rick Westera

Mặc dù không hoàn toàn cần thiết cho mẫu, nhưng tôi thấy rằng @property ở đây giúp truy cập sạch hơn từ mã ứng dụng , mặc dù có một hình phạt hiệu suất nhỏ liên quan (<30 ns trên máy tính xách tay của tôi). Tất nhiên đây là vấn đề của phong cách và mang tính chủ quan cao.
tawmas

Trong trường hợp bạn muốn sắp xếp tập hợp theo hai thuộc tính, đây là lệnh: class Meta: order = ['last_name', 'first_name']
Tms91

135

Bạn có thể sử dụng dictsort bộ lọc mẫu https://docs.djangoproject.com/en/dev/ref/templates/builtins/#std:templatefilter-dictsort

Điều này sẽ hoạt động:

{% for event in eventsCollection %}
   {{ event.location }}
   {% for attendee in event.attendee_set.all|dictsort:"last_name" %}
     {{ attendee.first_name }} {{ attendee.last_name }}
   {% endfor %}
 {% endfor %}

22
Tuyệt quá ! Và đối với những người thắc mắc, cũng có dictsortreversed: docs.djangoproject.com/en/dev/ref/templates/builtins/…
Mickaël

1
Trích dẫn từ bài viết gốc của tôi: à, nếu chỉ một bộ truy vấn là một bộ từ điển sẽ thực hiện công việc, nhưng nó không phải và nó không.
Dale Wilson

Tôi nghĩ rằng điều này sẽ ít hơn trong thực tế và hãy để mô hình xử lý việc sắp xếp trước khi tìm nạp các bản ghi.
acpmasquerade

1
@DaleWilson, tôi thực sự đã dictsortlàm việc đúng cách trên mã gần giống như mã của bạn. Điều thú vị là nó có vẻ hoạt động tốt trên các tập truy vấn.
mlissner

2
Và chỉ để rõ ràng hơn, không gian quan trọng: {% for attendee in event.attendee_set.all|dictsort:"last_name" %}sắp xếp những người tham dự, nhưng {% for attendee in event.attendee_set.all | dictsort:"last_name" %}cố gắng sắp xếp đầu ra của vòng lặp for và phá vỡ for.
mattsl

3

Một giải pháp là tạo một thẻ tạm thời tùy chỉnh:

@register.filter
def order_by(queryset, args):
    args = [x.strip() for x in args.split(',')]
    return queryset.order_by(*args)

sử dụng như thế này:

{% for image in instance.folder.files|order_by:"original_filename" %}
   ...
{% endfor %}

0

tập hợp lại sẽ có thể làm những gì bạn muốn, nhưng có lý do gì bạn không thể sắp xếp chúng theo cách bạn muốn trở lại trong chế độ xem?


Để sắp xếp chúng trong dạng xem, tôi sẽ cần phải lặp lại các sự kiện và đối với mỗi sự kiện, hãy tạo một vùng chứa của một số loại người tham dự có liên quan đến sự kiện đó theo thứ tự được sắp xếp đúng, sau đó chuyển toàn bộ bộ sưu tập các vùng chứa đó vào mẫu trong một biểu mẫu sẽ cho phép mẫu tìm thấy tập hợp người tham dự thích hợp khi lặp lại qua các sự kiện. Như tôi đã nói, nó có thể được thực hiện, nhưng nó không phải là một giải pháp tốt. Nó đòi hỏi quá nhiều khớp nối giữa chế độ xem và mẫu, lặp lại song song, v.v. Tôi đã hy vọng giải pháp tốt hơn cho những gì nên là một vấn đề chung.
Dale Wilson

Tôi đã xem xét tập hợp lại và nó dường như không làm những gì tôi muốn. cụ thể là tài liệu nói: [quote] Lưu ý rằng {% regroup%} không sắp xếp đầu vào của nó! Ví dụ của chúng tôi dựa trên thực tế là ngay từ đầu danh sách người đã được sắp xếp theo giới tính. [endquote]
Dale Wilson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.