Jak dodać wiele argumentów do mojego niestandardowego filtru szablonu w szablonie django?

89

Oto mój niestandardowy filtr:

from django import template

register = template.Library()

@register.filter
def replace(value, cherche, remplacement):
    return value.replace(cherche, remplacement)

a oto sposoby, w jakie próbowałem go użyć w moim pliku szablonu, które spowodowały błąd:

{{ attr.name|replace:"_"," " }}
{{ attr.name|replace:"_" " " }}
{{ attr.name|replace:"_":" " }}
{{ attr.name|replace:"cherche='_', remplacement=' '" }}

Spojrzałem w docs Django i książki , ale tylko znaleźć przykład za pomocą jednego argumentu ... czy to w ogóle możliwe?

bchhun
źródło

Odpowiedzi:

108

Jest to możliwe i dość proste.

Django dopuszcza tylko jeden argument do twojego filtra, ale nie ma powodu, dla którego nie możesz umieścić wszystkich argumentów w jednym łańcuchu, używając przecinka do ich oddzielenia.

Na przykład, jeśli chcesz filtr, który sprawdza, czy zmienna X znajduje się na liście [1,2,3,4], będziesz potrzebować filtru szablonu, który wygląda następująco:

{% if X|is_in:"1,2,3,4" %}

Teraz możemy stworzyć Twój szablon w następujący sposób:

from django.template import Library

register = Library()

def is_in(var, args):
    if args is None:
        return False
    arg_list = [arg.strip() for arg in args.split(',')]
    return var in arg_list

register.filter(is_in)

Linia, która tworzy arg_list, jest wyrażeniem generatora, które dzieli łańcuch args na wszystkie przecinki i wywołuje .strip () w celu usunięcia wszelkich spacji wiodących i końcowych.

Jeśli na przykład trzeci argument jest liczbą int, po prostu wykonaj:

arg_list[2] = int(arg_list[2])

Lub jeśli wszystkie z nich to int:

arg_list = [int(arg) for arg in args.split(',')]

EDYCJA: teraz, aby konkretnie odpowiedzieć na twoje pytanie, używając par klucz, wartość jako parametrów, możesz użyć tej samej klasy, której Django używa do parsowania ciągów zapytań z adresu URL, co z kolei ma również tę zaletę, że obsługuje kodowanie znaków zgodnie z twoimi ustawieniami. .

Tak więc, podobnie jak w przypadku ciągów zapytań, każdy parametr jest oddzielony znakiem „&”:

{{ attr.name|replace:"cherche=_&remplacement= " }}

Twoja funkcja zamiany będzie teraz wyglądać następująco:

from django import template
from django.http import QueryDict

register = template.Library()

@register.filter
def replace(value, args):
    qs = QueryDict(args)
    if qs.has_key('cherche') and qs.has_key('remplacement'):
        return value.replace(qs['cherche'], qs['remplacement'])
    else:
        return value

Możesz to nieco przyspieszyć, ryzykując wykonanie nieprawidłowych wymian:

qs = QueryDict(args)
return value.replace(qs.get('cherche',''), qs.get('remplacement',''))
Van Gale
źródło
1
Jeśli wartości tych są w zmiennych, jak to zaimplementować ...?
Anto
2
Wydawało się to pomocne, ale nie mogłem zmusić go do pracy z przekazywanymi zmiennymi. Aby to zrobić, użyłem taglub simple_tag- co pozwala na przekazywanie wielu zmiennych, nawet nazwanych.
Furbeenator
18

Niemożliwe zgodnie z tą sekcją dokumentów:

Filtry niestandardowe to po prostu funkcje Pythona, które pobierają jeden lub dwa argumenty:

  • Wartość zmiennej (wejście) - niekoniecznie ciąg.
  • Wartość argumentu - może mieć wartość domyślną lub zostać całkowicie pominięta.
Jeff Bauer
źródło
Podejście Van Gale'a zadziała, jeśli używasz napisów zakodowanych na stałe. Bilet Django [ code.djangoproject.com/ticket/1199] obsługuje wiele argumentów w niestandardowym filtrze i poprawka została zaakceptowana.
Jeff Bauer
17

To takie proste.

@register.filter(name='one_more')
def one_more(_1, _2):
    return _1, _2

def your_filter(_1_2, _3)
    _1, _2 = _1_2
    print "now you have three arguments, enjoy"

{{ _1|one_more:_2|your_filter:_3 }}
gshmu
źródło
Naprawdę super dziękuję za to rozwiązanie. Trochę go ulepszyłem, abyś mógł łączyć różne długości parametrów. gist.github.com/BrnoPCmaniak/e9552294b3059461f940a47143f58811
Filip Dobrovolný
1
To powinna być poprawna odpowiedź! To piękne rozwiązanie w Pythonie (może nie najlepsze rozwiązanie django, zobacz odpowiedź @dragonroot)
Antoine Draune
15

Zamiast filtra zarejestruj swój tag jako prosty tag. Mogą przyjmować wiele argumentów. Składnia wywołania będzie trochę inna, ale to tylko zmiana cukru składniowego.

dragonroot
źródło
2
To była poprawna odpowiedź na mój problem. Aby przekazać zmienną szablonu do tej funkcji, musiałem użyć pliku simple_tag.
Furbeenator
1
To jest dobre rozwiązanie. Zdecydowanie warto sprawdzić dokumentację django pod kątem prostego tagu: docs.djangoproject.com/en/1.8/howto/custom-template-tags/ ...
Gunther
6

To jest prostsze niż myślisz

Możesz do tego użyć simple_tag .

@register.simple_tag
def multiple_args_tag(a, b, c, d):
   #do your stuff
   return 

W szablonie :

{% multiple_args_tag 'arg1' 'arg2' 'arg3' 'arg4' %}

UWAGA: Nie zapomnij ponownie uruchomić serwera.

Sawan Chauhan
źródło
4

Ta funkcja została oznaczona jako WONTFIX w 2013 Django's Trac: http://code.djangoproject.com/ticket/1199

bchhun
źródło
To zgłoszenie zostało zamknięte jako WONTFIX w zeszłym roku (2013), ich programista sugeruje użycie niestandardowego tagu, jeśli potrzebujesz wielu argumentów.
Paul Lo
3

<moja-witryna> /globaltags/replace.py

from django.template import Library

import re

register = Library()

def search(value, search):
    return re.sub(search, '#f4x@SgXXmS', value)

def replace(value, replace):
    return re.sub('#f4x@SgXXmS', replace, value)

register.filter(search)
register.filter(replace)

W szablonie:

{{ "saniel"|search:"s"|replace:"d" }}
theosp
źródło
Byłoby miło, gdybyś #f4x@SgXXmStrochę wyjaśnił ?
Dan Abramov
1
po prostu losowy ciąg używany jako symbol zastępczy. Wybrałem ten ciąg, ponieważ uważałem, że nie będzie częścią ciągu wejściowego. Jeśli na przykład użyłem "{}" zamiast '# f4x @ SgXXmS' {{"użyj {} zamiast off []" | search: "off" | replace: "of"}} zwróci: "użycie zamiast [] "a nie oczekiwany wynik:" użyj {} zamiast [] "
theosp
5
Och, to ma sens. Miło byłoby uznać to za SUBSTRING_THAT_NEVER_OCCURSmyśl.
Dan Abramov
-1

Możesz po prostu zrobić to:

{% assign find_total_issued = dailysalesreport | find: "TotalIssued":"13" %}

public static List<object> Find(object collection, string column, string value)

I dotrze do celu, tak jak abstrakcja funkcji sjare.

Saad Hasnain Khan
źródło
-2

Oto zły pomysł, ale działa:

{{ xml|input_by_xpath:"{'type':'radio','xpath':'//result/value'}" }}

i

@register.filter
def input_by_xpath(device, args): 
    args = eval(args)
    ...
    result = "<input type=\"%s\" value=\"%s\" name=\"%s\"/>"%(args['type'],value,args['xpath'])
    return mark_safe(result)

źródło