Django şablonlarında sorgu filtrelemeyi nasıl gerçekleştiririm


83

Bir görünümdeki python koduna eşdeğer bir nesne kümesi elde etmek için django şablonundan filtrelenmiş bir sorgu gerçekleştirmem gerekiyor:

queryset = Modelclass.objects.filter(somekey=foo)

Şablonumda yapmak istiyorum

{% for object in data.somekey_set.FILTER %}

ama nasıl FİLTRE yazacağımı bulamıyorum.

Yanıtlar:


121

Bunu yapamazsınız, ki bu tasarım gereğidir. Django çerçeve yazarları, sunum kodunun veri mantığından katı bir şekilde ayrılmasını amaçladı. Filtreleme modelleri veri mantığıdır ve HTML çıktısını almak sunum mantığıdır.

Yani birkaç seçeneğiniz var. En kolayı filtrelemeyi yapmak ve ardından sonucu 'a iletmektir render_to_response. Ya da modelinizde söyleyebileceğiniz bir yöntem yazabilirsiniz {% for object in data.filtered_set %}. Son olarak, kendi şablon etiketinizi yazabilirsiniz, ancak bu özel durumda buna karşı bir tavsiyede bulunacağım.


2
Merhaba İnsanlar artık 2014! Yaklaşık 6 yıl sonra JS kitaplıkları büyük ilerleme kaydetti ve çok büyük olmayan verilerin filtrelenmesi, bazı güzel java komut dosyası kitaplığı veya en azından AJAX-ed desteğiyle istemci tarafında yapılmalıdır.
andilabs

1
@andi: Orta derecede büyük veri kümeleri için bile kesinlikle katılıyorum, örneğin bir tablodaki binlerce satır. Milyonlarca satırlık veritabanları üzerinde çalışmış
olsaydınız

elbette ama ben sadece sık sık birkaç K satırla uğraşan insanların, tarayıcıda kullanıcı için hoş bir etkileşim tecrübesi olabileceğine işaret etmek istedim. Ve hatta büyük veri kümeleriyle uğraşan insanlar için bazı hibrit yaklaşımlar iyi bir çözüm olabilir, örneğin sunucu tarafında birkaç M ila birkaç K ve bu birkaç K içindeki diğer daha hafif personel istemci tarafında yapar.
andilabs

9
@andi İstemci tarafında asla yapılmayacak izinlere göre içeriği filtrelediğiniz durumlar hariç . Sağ?

40

Bunun gibi fazladan bir şablon etiketi ekledim:

@register.filter
def in_category(things, category):
    return things.filter(category=category)

O zaman yapabilirim:

{% for category in categories %}
  {% for thing in things|in_category:category %}
    {{ thing }}
  {% endfor %}
{% endfor %}

Bu çözümü çalışıyorum ama bir hata tetikleme tutmak: 'for' statements should use the format 'for x in y': for p in r | people_in_roll_department:d. Herhangi bir fikir?
diosney

@diosney muhtemelen şeyler cümlesine ".all" eklemeniz gerekir. "
Things.all

12

Bu problemle düzenli olarak karşılaşıyorum ve sıklıkla "yöntem ekle" çözümünü kullanıyorum. Ancak, kesinlikle "bir yöntem ekle" veya "görünümde hesapla" nın çalışmadığı (veya iyi çalışmadığı) durumlar vardır. Örneğin, şablon parçalarını önbelleğe alırken ve onu üretmek için önemsiz olmayan bazı DB hesaplamalarına ihtiyaç duyduğunuzda. Gerekmedikçe DB çalışması yapmak istemezsiniz, ancak şablon mantığının derinlerine inene kadar buna ihtiyacınız olup olmadığını bilemezsiniz.

Diğer olası çözümler:

  1. Http://www.djangosnippets.org/snippets/9/ adresinde bulunan {% expr <expression> as <var_name>%} şablon etiketini kullanın İfade, yerel kapsamınız olarak şablonunuzun Bağlamına sahip herhangi bir yasal Python ifadesidir.

  2. Şablon işlemcinizi değiştirin. Jinja2 ( http://jinja.pocoo.org/2/ ) Django şablon diliyle hemen hemen aynı olan ancak Python gücünün tamamı mevcut olan sözdizimine sahiptir. Aynı zamanda daha hızlı. Bunu toptan yapabilirsiniz, aksi takdirde bu şablonlara kullanımını kısıtlayabilir sen üzerinde çalışıyoruz, ama tasarımcı bakımlı sayfalar için Django'nın "güvenli" şablonları kullanın.


9

Diğer seçenek, her zaman uygulanmasını istediğiniz bir filtreniz varsa, söz konusu modele, filtreyi döndürülen sonuçlara her zaman uygulayan özel bir yönetici eklemektir .

Bunun güzel bir örneği, Eventmodel üzerinde yaptığınız sorguların% 90'ında buna benzer bir şey isteyeceğiniz Event.objects.filter(date__gte=now), yani normalde Eventsgelecek olanlarla ilgileneceğiniz bir modeldir . Bu şöyle görünür:

class EventManager(models.Manager):
    def get_query_set(self):
        now = datetime.now()
        return super(EventManager,self).get_query_set().filter(date__gte=now)

Ve modelde:

class Event(models.Model):
    ...
    objects = EventManager()

Ancak yine, bu aynı filtreyi Eventmodelde yapılan tüm varsayılan sorgulara uygular ve bu nedenle yukarıda açıklanan tekniklerin bazıları kadar esnek değildir.


9

Bu, bir atama etiketiyle çözülebilir:

from django import template

register = template.Library()

@register.assignment_tag
def query(qs, **kwargs):
    """ template tag which allows queryset filtering. Usage:
          {% query books author=author as mybooks %}
          {% for book in mybooks %}
            ...
          {% endfor %}
    """
    return qs.filter(**kwargs)

4
assignment_tag Django 2.0'da kaldırıldı
Andreas Bergström

1

2020'de bir cevap arayanlar için. Bu benim için çalıştı.

Görünümlerde:

 class InstancesView(generic.ListView):
        model = AlarmInstance
        context_object_name = 'settings_context'
        queryset = Group.objects.all()
        template_name = 'insta_list.html'

        @register.filter
        def filter_unknown(self, aVal):
            result = aVal.filter(is_known=False)
            return result

        @register.filter
        def filter_known(self, aVal):
            result = aVal.filter(is_known=True)
            return result

Şablonda:

{% for instance in alarm.qar_alarm_instances|filter_unknown:alarm.qar_alarm_instances %}

Sözde kodda:

For each in model.child_object|view_filter:filter_arg

Umarım yardımcı olur.

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.