ฉันจะเพิ่มอาร์กิวเมนต์หลายรายการในตัวกรองเทมเพลตที่กำหนดเองในเทมเพลต django ได้อย่างไร


91

นี่คือตัวกรองที่กำหนดเองของฉัน:

from django import template

register = template.Library()

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

และนี่คือวิธีที่ฉันลองใช้ในไฟล์เทมเพลตที่ทำให้เกิดข้อผิดพลาด:

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

ฉันดูเอกสารและหนังสือของ djangoแต่พบเพียงตัวอย่างที่ใช้อาร์กิวเมนต์เดียว ... เป็นไปได้หรือไม่?

คำตอบ:


108

เป็นไปได้และค่อนข้างง่าย

Django อนุญาตเพียงอาร์กิวเมนต์เดียวในตัวกรองของคุณ แต่ไม่มีเหตุผลที่คุณไม่สามารถใส่อาร์กิวเมนต์ทั้งหมดลงในสตริงเดียวโดยใช้ลูกน้ำเพื่อแยกอาร์กิวเมนต์

ตัวอย่างเช่นหากคุณต้องการตัวกรองที่ตรวจสอบว่าตัวแปร X อยู่ในรายการ [1,2,3,4] หรือไม่คุณจะต้องมีตัวกรองเทมเพลตที่มีลักษณะดังนี้:

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

ตอนนี้เราสามารถสร้างเทมเพลตของคุณได้ดังนี้:

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)

บรรทัดที่สร้าง arg_list คือนิพจน์ตัวสร้างที่แยกสตริง args บนเครื่องหมายจุลภาคและการเรียก .strip () เพื่อลบช่องว่างนำหน้าและต่อท้าย

ตัวอย่างเช่นหากอาร์กิวเมนต์ที่ 3 เป็น int ให้ทำดังนี้

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

หรือถ้าทั้งหมดเป็น ints ให้ทำ:

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

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

ดังนั้นเช่นเดียวกับสตริงการค้นหาพารามิเตอร์แต่ละรายการจะถูกคั่นด้วย "&":

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

จากนั้นฟังก์ชันการแทนที่ของคุณจะมีลักษณะดังนี้:

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

คุณสามารถเร่งความเร็วได้โดยที่เสี่ยงต่อการเปลี่ยนที่ไม่ถูกต้อง:

qs = QueryDict(args)
return value.replace(qs.get('cherche',''), qs.get('remplacement',''))

1
หากค่าเหล่านี้อยู่ในตัวแปรจะใช้สิ่งนี้อย่างไร ... ?
Anto

2
สิ่งนี้ดูเหมือนจะมีประโยชน์ แต่ฉันไม่สามารถใช้งานได้กับตัวแปรที่ส่งผ่าน ในการทำเช่นนั้นฉันใช้tagหรือsimple_tag- ซึ่งอนุญาตให้มีหลายตัวแปรแม้กระทั่งตัวแปรที่ตั้งชื่อก็จะถูกส่งผ่าน
Furbeenator

18

ไม่สามารถทำได้ตามส่วนนี้ของเอกสาร:

ตัวกรองแบบกำหนดเองเป็นเพียงฟังก์ชัน Python ที่รับอาร์กิวเมนต์หนึ่งหรือสองอาร์กิวเมนต์:

  • ค่าของตัวแปร (อินพุต) - ไม่จำเป็นต้องเป็นสตริง
  • ค่าของอาร์กิวเมนต์ - ซึ่งอาจมีค่าเริ่มต้นหรือปล่อยทิ้งไว้ทั้งหมด

วิธีการของ Van Gale จะใช้ได้ผลหากคุณใช้สตริงแบบฮาร์ดโค้ด ตั๋ว Django [ code.djangoproject.com/ticket/1199]รองรับหลายอาร์กิวเมนต์ในตัวกรองแบบกำหนดเองและยอมรับโปรแกรมแก้ไขแล้ว
Jeff Bauer

17

ง่ายๆแบบนี้แหละ

@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 }}

ขอบคุณมากจริงๆสำหรับการแก้ปัญหานี้ ฉันได้อัปเกรดเล็กน้อยเพื่อให้คุณสามารถเชื่อมโยงพารามิเตอร์ที่มีความยาวต่างกันได้ gist.github.com/BrnoPCmaniak/e9552294b3059461f940a47143f58811
Filip Dobrovolný

1
นี่น่าจะเป็นคำตอบที่ถูกต้อง! เป็นโซลูชันหลามที่สวยงาม (อาจไม่ใช่โซลูชัน django ที่ดีที่สุดดูคำตอบ @dragonroot)
Antoine Draune

15

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


2
นี่คือคำตอบที่ถูกต้องสำหรับปัญหาของฉัน ในการส่งตัวแปรเทมเพลตไปยังฟังก์ชันนี้ฉันต้องใช้ไฟล์simple_tag.
Furbeenator

1
นี่เป็นทางออกที่ดี มันคุ้มค่าที่จะตรวจสอบเอกสาร django สำหรับแท็กง่ายๆ: docs.djangoproject.com/en/1.8/howto/custom-template-tags/…
Gunther

6

มันง่ายกว่าที่คุณคิด

คุณสามารถใช้simple_tagสำหรับสิ่งนี้

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

ในเทมเพลต :

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

หมายเหตุ: อย่าลืมเรียกใช้เซิร์ฟเวอร์อีกครั้ง


4

คุณลักษณะนี้ถูกทำเครื่องหมายเป็น WONTFIX ในปี 2013 Trac ของ Django: http://code.djangoproject.com/ticket/1199


ตั๋วนั้นถูกปิดเมื่อ WONTFIX เมื่อปีที่แล้ว (2013) ผู้พัฒนาแนะนำให้ใช้แท็กที่กำหนดเองหากต้องการอาร์กิวเมนต์หลายรายการ
Paul Lo

3

<my-site> /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)

ในเทมเพลต:

{{ "saniel"|search:"s"|replace:"d" }}

จะดีไหมถ้าคุณอธิบาย#f4x@SgXXmSสักหน่อย?
Dan Abramov

1
เพียงแค่สตริงสุ่มที่ใช้เป็นตัวยึด ฉันเลือกสตริงนี้เพราะฉันเชื่อว่ามันจะไม่เป็นส่วนหนึ่งของสตริงอินพุต ตัวอย่างเช่นหากฉันใช้ "{}" แทน "# f4x @ SgXXmS" {{"use {} แทน off []" | search: "off" | replace: "of"}} จะส่งกลับ: "use of แทนที่จะเป็น [] "และไม่ใช่ผลลัพธ์ที่คาดไว้:" use {} แทน [] "
theosp

6
โอ้นั่นเข้าท่า อาจจะเป็นการดีที่จะประกาศว่าเป็นSUBSTRING_THAT_NEVER_OCCURSความคิด
Dan Abramov

-1

คุณสามารถทำได้ง่ายๆ:

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

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

sjareและก็จะถึงปลายทางเป็นนามธรรมของการทำงานคือ


-2

นี่เป็นความคิดที่ไม่ดี แต่ใช้ได้ผล:

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

และ

@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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.