Bir Django şablonunda ilgili öğeleri sıralama


88

Bir DJango şablonunda bir dizi ilgili öğeyi sıralamak mümkün müdür?

Yani: bu kod (açıklık için HTML etiketleri çıkarılmıştır):

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

ekranlar neredeyse aynen istiyorum. Değiştirmek istediğim tek şey, soyadına göre sıralanacak katılımcılar listesidir. Bunun gibi bir şey söylemeyi denedim:

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

Ne yazık ki, yukarıdaki sözdizimi çalışmıyor (boş bir liste oluşturuyor) ve düşündüğüm başka bir varyasyon da yok (çok sayıda sözdizimi hatası bildirildi, ancak neşe yok).

Elbette, benim görüşüme göre bir dizi sıralı katılımcı listesi üretebilirdim, ancak bu çirkin ve kırılgan (ve çirkin) bir çözümden bahsetmiştim.

Söylemeye gerek yok, ama yine de söyleyeceğim, yararlı hiçbir şey bulmadan çevrimiçi belgeleri inceledim ve Stack Overflow ve django-user arşivlerini araştırdım (ah, eğer sadece bir sorgu kümesi bir sözlük olsaydı dictsort bunu yapardı iş, ama değil ve değil)

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

Tawmas'ın cevabını kabul ettikten sonra ek düşünceler eklemek için düzenlendi.


Tawmas sorunu tam olarak benim sunduğum gibi ele aldı - ancak çözüm beklediğim gibi değildi. Sonuç olarak, başka durumlarda da kullanılabilecek yararlı bir teknik öğrendim.

Tom'un cevabı OP'mde daha önce bahsettiğim ve "çirkin" olduğu için geçici olarak reddettiğim bir yaklaşım önerdi.

"Çirkin" bir içgüdüsel tepkiydi ve bunda neyin yanlış olduğunu açıklığa kavuşturmak istedim. Bunu yaparken, bunun çirkin bir yaklaşım olmasının sebebinin, işlenecek şablona bir sorgu seti geçirme fikrine takılıp kalmış olmam olduğunu fark ettim. Bu gereksinimi gevşetirsem, işe yaraması gereken çirkin bir yaklaşım vardır.

Bunu henüz denemediyseniz, daha ziyade Sorgu Kümesi geçen daha, görünüm kod Olaylar, daha sonra ilgili katılımcılar için bir sorgu seti ile her Olay dekore bir liste üreten sorgu kümesi yineledi varsayalım değil WAS , sıralı (veya filtrelenmiş ya da her neyse) istenen şekilde. Öyle bir şey:

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)

Şimdi şablon şu hale gelir:

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

Dezavantajı ise, görüşün tüm olayları aynı anda "gerçekleştirmesi" gerektiğidir ve bu, çok sayıda olay olması durumunda sorun olabilir. Elbette sayfalandırma da eklenebilir, ancak bu görünümü oldukça karmaşık hale getirir.

Bunun tersi, "görüntülenecek verileri hazırlayın" kodunun ait olduğu görünümde olması, şablonun, görünüm tarafından görüntülenmek üzere sağlanan verileri biçimlendirmeye odaklanmasını sağlar. Bu doğru ve uygun.

Bu yüzden planım, büyük tablolar için Tawmas tekniğini ve küçük tablolar için yukarıdaki tekniği, okuyucuya bırakılan büyük ve küçük tanımıyla (sırıtma) kullanmaktır.

Yanıtlar:


137

Katılımcı modelinde sıralamayı şu şekilde belirtmeniz gerekir. Örneğin (model sınıfınızın Attendee olarak adlandırıldığı varsayılarak):

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

Daha fazla referans için kılavuza bakın .

DÜZENLE . Başka bir çözüm de, şablonunuzdan erişebileceğiniz bir özelliği Etkinlik modelinize eklemektir:

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

Bunlardan daha fazlasını ihtiyaç duyduğunuzda tanımlayabilirsiniz ...


Yorumunuz için teşekkürler, ancak bu yalnızca gösterim siparişini katılımcının kalıcı bir mülkü haline getirmek istersem işe yarar, ki bunu yapmıyorum. Örneğin, katılımcıları kayıtlarının alındığı tarihe göre sıralanmış olarak görüntülemek isteyebilirim, böylece hangi katılımcılara onlar için yer olmadığının bildirilmesi gerektiğini bilirim.
Dale Wilson

Sizin için alternatif bir çözüm ekledim. İhtiyacınız olan esnekliği size sağlamalıdır.
Tawmas

@Mark Gerçekten de öyle. Anladığım kadarıyla, @propertydahil olan alıcı veya ayarlayıcı olmadığı için burada aşırı
yetenek var

Şablon için kesinlikle gerekli olmasa da, buradaki @ özelliğinin uygulama kodundan daha temiz erişim sağladığını görüyorum , ancak küçük bir performans cezası söz konusu olsa da (dizüstü bilgisayarımda <30 ns). Bu elbette bir stil meselesi ve oldukça öznel.
Tawmas


140

Şablon filtre dictsort'u https://docs.djangoproject.com/en/dev/ref/templates/builtins/#std:templatefilter-dictsort kullanabilirsiniz

Bu çalışmalı:

{% 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
Harika ! Merak edenler için ayrıca dictsortreversed: docs.djangoproject.com/en/dev/ref/templates/builtins/…
Mickaël

1
Orijinal yazımdan alıntı yapacak olursak: ah, eğer sadece bir sorgu kümesi bir sözlük dictsort olsaydı işi yapardı, ama değil ve değil.
Dale Wilson

Bunun pratikte daha az olması gerektiğini düşünüyorum ve kayıtları getirmeden önce modelin sıralamayı halletmesine izin verin.
acpmasquerade

1
@DaleWilson, aslında dictsortneredeyse tamamen sizinki gibi kod üzerinde düzgün çalışıyorum. İlginç bir şekilde sorgu kümelerinde iyi çalışıyor gibi görünüyor.
mlissner

2
Ve sadece daha fazla netlik sağlamak için boşluklar önemlidir: {% for attendee in event.attendee_set.all|dictsort:"last_name" %}katılımcıları sıralar, ancak {% for attendee in event.attendee_set.all | dictsort:"last_name" %}for döngüsünün çıktısını sıralamaya çalışır ve for.
mattsl

5

Çözümlerden biri, özel bir şablon etiketi yapmaktır:

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

bunun gibi kullanın:

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

0

yeniden gruplama istediğinizi yapabilmelidir, ancak görünümde istediğiniz şekilde onları sipariş edememenizin bir nedeni var mı?


Bunları görünümde sıralamak için olayları yinelemem ve her etkinlik için, uygun şekilde sıralanmış bir sırada bu etkinlikle ilgili bir tür katılımcıdan bir kap oluşturmalı ve ardından bu kapsayıcı koleksiyonunun tamamını şablona, olarak şablon katılımcı uygun koleksiyon bulalım olur o olayları yineledi. Dediğim gibi yapılabilir ama bu iyi bir çözüm değil. Görünüm ile şablon, paralel yinelemeler vb. Arasında çok fazla bağlantı gerektirir. Ortak bir problem olması gereken şey için daha iyi bir çözüm bulmayı umuyordum.
Dale Wilson

Yeniden gruba baktım ve istediğimi yapmıyor gibi görünüyordu. özellikle dokümantasyon şunları söylüyor: [alıntı] {% regroup%} girişini sipariş etmemektedir! Örneğimiz, kişi listesinin ilk etapta cinsiyete göre sıralandığı gerçeğine dayanmaktadır. [endquote]
Dale Wilson
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.