การจัดเรียงรายการที่เกี่ยวข้องในเทมเพลต Django


88

เป็นไปได้ไหมที่จะจัดเรียงชุดรายการที่เกี่ยวข้องในเทมเพลต DJango

นั่นคือ: รหัสนี้ (ที่ละไว้แท็ก HTML เพื่อความชัดเจน):

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

แสดงเกือบจะตรงกับที่ฉันต้องการ สิ่งเดียวที่ฉันต้องการเปลี่ยนคือฉันรายชื่อผู้เข้าร่วมที่จะจัดเรียงตามนามสกุล ฉันได้ลองพูดสิ่งนี้แล้ว:

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

อนิจจาไวยากรณ์ข้างต้นใช้ไม่ได้ (สร้างรายการว่างเปล่า) และไม่มีรูปแบบอื่นใดที่ฉันคิดไว้ (รายงานข้อผิดพลาดทางไวยากรณ์จำนวนมาก แต่ไม่มีความสุข)

แน่นอนฉันสามารถสร้างรายชื่อผู้เข้าร่วมที่จัดเรียงไว้ในมุมมองของฉันได้ แต่นั่นเป็นวิธีแก้ปัญหาที่น่าเกลียดและเปราะบาง (และฉันพูดถึงวิธีที่น่าเกลียดหรือไม่)

ไม่จำเป็นต้องพูด แต่ฉันจะพูดต่อไปฉันได้อ่านเอกสารออนไลน์และค้นหา Stack Overflow และที่เก็บถาวรของผู้ใช้ django โดยไม่พบสิ่งใดที่เป็นประโยชน์ (อ่าถ้ามีเพียงชุดการสืบค้นเป็นคำสั่งพจนานุกรมเท่านั้นที่จะทำ งาน แต่มันไม่ใช่และมันไม่)

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

แก้ไขเพื่อเพิ่มความคิดเพิ่มเติมหลังจากยอมรับคำตอบของ Tawmas


Tawmas แก้ไขปัญหาตรงตามที่ฉันนำเสนอ - แม้ว่าวิธีแก้ปัญหาจะไม่ใช่สิ่งที่ฉันคาดหวังก็ตาม ด้วยเหตุนี้ฉันจึงได้เรียนรู้เทคนิคที่มีประโยชน์ซึ่งสามารถนำไปใช้ในสถานการณ์อื่น ๆ ได้เช่นกัน

คำตอบของทอมเสนอแนวทางที่ฉันได้กล่าวไปแล้วใน OP ของฉันและปฏิเสธอย่างไม่เป็นทางการว่า "น่าเกลียด"

"น่าเกลียด" เป็นปฏิกิริยาทางเดินอาหารและฉันต้องการชี้แจงว่าเกิดอะไรขึ้น ในการทำเช่นนั้นฉันตระหนักว่าเหตุผลที่มันเป็นแนวทางที่น่าเกลียดเป็นเพราะฉันติดอยู่กับความคิดที่จะส่งแบบสอบถามที่ตั้งค่าไปยังเทมเพลตที่จะแสดงผล หากฉันผ่อนคลายความต้องการนั้นมีวิธีการที่ไม่น่าเกลียดที่ควรได้ผล

ฉันยังไม่ได้ลองสิ่งนี้ แต่สมมติว่าแทนที่จะส่งแบบสอบถามรหัสมุมมองจะวนซ้ำผ่านชุดแบบสอบถามที่สร้างรายการเหตุการณ์จากนั้นตกแต่งแต่ละเหตุการณ์ด้วยชุดแบบสอบถามสำหรับผู้เข้าร่วมที่เกี่ยวข้องซึ่งเรียงลำดับWAS (หรือกรองแล้ว หรืออะไรก็ได้) ในแบบที่ต้องการ สิ่งที่ต้องการ:

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)

ตอนนี้เทมเพลตกลายเป็น:

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

ข้อเสียคือมุมมองต้อง "เข้าใจ" เหตุการณ์ทั้งหมดในคราวเดียวซึ่งอาจเป็นปัญหาได้หากมีเหตุการณ์จำนวนมาก แน่นอนว่าเราสามารถเพิ่มเลขหน้าได้ แต่จะทำให้มุมมองซับซ้อนขึ้นมาก

ด้านบนคือโค้ด "เตรียมข้อมูลที่จะแสดง" อยู่ในมุมมองที่เป็นของโดยให้เทมเพลตมุ่งเน้นไปที่การจัดรูปแบบข้อมูลที่ได้รับจากมุมมองสำหรับการแสดงผล นี่คือสิ่งที่ถูกต้องและเหมาะสม

ดังนั้นแผนของฉันคือใช้เทคนิคของ Tawmas สำหรับตารางขนาดใหญ่และเทคนิคข้างต้นสำหรับตารางขนาดเล็กโดยมีคำจำกัดความของขนาดใหญ่และขนาดเล็กให้กับผู้อ่าน (ยิ้ม)

คำตอบ:


137

คุณต้องระบุการสั่งซื้อในรูปแบบผู้เข้าร่วมเช่นนี้ ตัวอย่างเช่น (สมมติว่าคลาสโมเดลของคุณชื่อ Attendee):

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

ดูคู่มือสำหรับการอ้างอิงเพิ่มเติม

แก้ไข อีกวิธีหนึ่งคือการเพิ่มคุณสมบัติให้กับโมเดลเหตุการณ์ซึ่งคุณสามารถเข้าถึงได้จากเทมเพลตของคุณ

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

คุณสามารถกำหนดสิ่งเหล่านี้ได้มากขึ้นตามที่คุณต้องการ ...


ขอบคุณสำหรับความคิดเห็นของคุณ แต่จะใช้ได้ก็ต่อเมื่อฉันต้องการให้คำสั่งการแสดงเป็นทรัพย์สินถาวรของผู้เข้าร่วมซึ่งฉันไม่ ตัวอย่างเช่นฉันอาจต้องการแสดงผู้เข้าร่วมโดยเรียงตามวันที่ที่ได้รับการลงทะเบียนดังนั้นฉันจะทราบว่าผู้เข้าร่วมคนใดควรได้รับแจ้งว่าไม่มีที่ว่างสำหรับพวกเขา
Dale Wilson

ฉันได้เพิ่มทางเลือกอื่นสำหรับคุณแล้ว ควรให้ความยืดหยุ่นที่คุณต้องการ
tawmas

@ มาร์คแน่นอนมันทำ เท่าที่ฉันเข้าใจ@propertyก็คือที่นี่มากเกินไปเนื่องจากไม่มี getters หรือ setters เกี่ยวข้อง: stackoverflow.com/questions/1554546/…
Rick Westera

แม้ว่าจะไม่จำเป็นอย่างยิ่งสำหรับเทมเพลต แต่ฉันพบว่า @property ที่นี่ทำให้การเข้าถึงที่สะอาดขึ้นจากรหัสแอปพลิเคชันแม้ว่าจะมีการลงโทษด้านประสิทธิภาพเล็กน้อยก็ตาม (<30 ns บนแล็ปท็อปของฉัน) แน่นอนว่านี่เป็นเรื่องของรูปแบบและมีความเป็นส่วนตัวสูง
tawmas

ในกรณีที่คุณต้องการจัดเรียงชุดที่เกี่ยวข้องกับแอตทริบิวต์สองรายการนี่คือคำสั่ง: class Meta:
orders

140

คุณสามารถใช้ตัวกรองเทมเพลตdictsort https://docs.djangoproject.com/en/dev/ref/templates/builtins/#std:templatefilter-dictsort

สิ่งนี้ควรใช้งานได้:

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

23
เยี่ยมมาก! และสำหรับผู้ที่สงสัยว่ายังมีdictsortreversed: docs.djangoproject.com/en/dev/ref/templates/builtins/...
Mickael

1
หากต้องการอ้างอิงจากโพสต์ต้นฉบับของฉัน: อาถ้ามีเพียงชุดคำค้นหาเป็นคำสั่งพจนานุกรมจะทำงานได้ แต่ก็ไม่ใช่และไม่ทำเช่นนั้น
Dale Wilson

ฉันคิดว่าสิ่งนี้ควรจะน้อยกว่าในทางปฏิบัติและปล่อยให้โมเดลจัดการการเรียงลำดับก่อนที่จะดึงข้อมูลบันทึก
acpmasquerade

1
@DaleWilson ฉันdictsortทำงานได้ดีกับโค้ดเกือบจะเหมือนกับของคุณ น่าสนใจดูเหมือนว่าจะทำงานได้ดีกับแบบสอบถาม
mlissner

2
และเพื่อความชัดเจนยิ่งขึ้นช่องว่างมีความสำคัญ: จัด {% for attendee in event.attendee_set.all|dictsort:"last_name" %}เรียงผู้เข้าร่วม แต่{% for attendee in event.attendee_set.all | dictsort:"last_name" %}พยายามเรียงลำดับผลลัพธ์ของลูป for และแบ่งไฟล์for.
mattsl

5

ทางออกหนึ่งคือการสร้างเทมเพลตที่กำหนดเอง:

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

ใช้แบบนี้:

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

0

การจัดกลุ่มใหม่ควรจะสามารถทำในสิ่งที่คุณต้องการได้ แต่มีเหตุผลที่คุณไม่สามารถสั่งพวกเขาในแบบที่คุณต้องการกลับมาได้หรือไม่?


ในการจัดลำดับในมุมมองฉันจะต้องวนซ้ำผ่านเหตุการณ์และสำหรับแต่ละเหตุการณ์ให้สร้างคอนเทนเนอร์ของผู้เข้าร่วมบางประเภทที่เกี่ยวข้องกับเหตุการณ์นั้นตามลำดับที่ถูกต้องจากนั้นส่งต่อคอลเล็กชันคอนเทนเนอร์ทั้งหมดนั้นไปยังเทมเพลตในรูปแบบที่ จะช่วยให้แม่แบบพบคอลเลกชันที่เหมาะสมของผู้เข้าร่วมประชุมเป็นมันซ้ำผ่านเหตุการณ์ที่เกิดขึ้น อย่างที่บอกมันทำได้ แต่ไม่ใช่ทางออกที่ดี มันต้องใช้การเชื่อมต่อระหว่างมุมมองและเทมเพลตมากเกินไปการทำซ้ำแบบขนาน ฯลฯ ฉันหวังว่าจะได้วิธีแก้ปัญหาที่ดีกว่าสำหรับสิ่งที่ควรเป็นปัญหาทั่วไป
Dale Wilson

ฉันมองไปที่การจัดกลุ่มใหม่และดูเหมือนว่าจะไม่ทำตามที่ฉันต้องการ โดยเฉพาะอย่างยิ่งเอกสารระบุว่า: [quote] โปรดทราบว่า {% regroup%} ไม่ได้สั่งการป้อนข้อมูล! ตัวอย่างของเราขึ้นอยู่กับข้อเท็จจริงที่ว่ารายชื่อบุคคลเรียงลำดับตามเพศตั้งแต่แรก [endquote]
Dale Wilson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.