Я знаю, что здесь есть сообщение: система шаблонов django, вызывая функцию внутри модели, описывая, как вы можете создать собственный фильтр шаблонов для этого, но из точка зрения программиста - это провал, потому что он взламывает то, что не предназначено для этого. Кажется почти смешным, что вы не можете вызвать метод с параметрами в системе шаблонов Django.
Как использовать параметры метода в шаблоне Django?
Ответ 1
Команда Django решила, как философия, не допускать передачу параметров метода в представление. Лично я согласен с ними; это заставляет разделять логику и представление, которые я нахожу полезными. Это предотвращает тип кода спагетти, для которого печально известен PHP.
Правильная вещь в том случае, если вы связаны, - это передать результат этого вызова из представления в шаблон через контекст. Это просто более удобно. Если позже вам нужно изменить my_related_deltas(3)
на my_related_deltas(4)
, вы перейдете к представлению, которое должно быть достаточно кратким, а не искать через шаблоны, чтобы выяснить, где именно оно определено.
Ответ 2
Несмотря на то, что авторы django предлагают не кормить наши методы аргументами, которые вы все еще можете сделать, используя этот "маленький" тег шаблона, который я написал.
В моем примере я просто показываю, что это возможно. Для причин безопасности Я настоятельно рекомендую вам написать templatetags вместо того, чтобы пытаться передать аргументы методам модели.
! ПРЕДУПРЕЖДЕНИЕ! это только для целей тестирования! Используя это, вы можете взломать NASA, а также вас могут убить.
class CallNode(template.Node):
def __init__(self,object, method, args=None, kwargs=None, context_name=None):
self.object = template.Variable(object)
self.method = method
if args:
self.args = []
for arg in args:
self.args.append(template.Variable(arg))
else:
self.args = None
if kwargs:
self.kwargs = {}
for key in kwargs:
self.kwargs[key] = template.Variable(kwargs[key])
else:
self.kwargs = None
self.context_name = context_name
def render(self, context):
object = self.object.resolve(context)
if isinstance(object, str):
raise template.TemplateSyntaxError('Given object is string ("%s") of length %d'
% (object, len(object)))
args = []
kwargs = {}
if self.args:
for arg in self.args:
args.append(arg.resolve(context))
if self.kwargs:
for key in self.kwargs:
kwargs[key] = self.kwargs[key].resolve(context)
method = getattr(object, self.method, None)
if method:
if hasattr(method, '__call__'):
result = method(*args, **kwargs)
else:
result = method
if self.context_name:
context[self.context_name] = result
return ''
else:
if not result == None:
return result
else:
return ''
else:
raise template.TemplateSyntaxError('Model %s doesn\'t have method "%s"'
% (object._meta.object_name, self.method))
@register.tag
def call(parser, token):
"""
Passes given arguments to given method and returns result
Syntax::
{% call <object>[.<foreignobject>].<method or attribute> [with <*args> <**kwargs>] [as <context_name>] %}
Example usage::
{% call article.__unicode__ %}
{% call article.get_absolute_url as article_url %}
{% call article.is_visible with user %}
{% call article.get_related with tag 5 as related_articles %}
{% call object.foreign_object.test with other_object "some text" 123 article=article text="some text" number=123 as test %}
"""
bits = token.split_contents()
syntax_message = ("%(tag_name)s expects a syntax of %(tag_name)s "
"<object>.<method or attribute> [with <*args> <**kwargs>] [as <context_name>]" %
dict(tag_name=bits[0]))
temp = bits[1].split('.')
method = temp[-1]
object = '.'.join(temp[:-1])
# Must have at least 2 bits in the tag
if len(bits) > 2:
try:
as_pos = bits.index('as')
except ValueError:
as_pos = None
try:
with_pos = bits.index('with')
except ValueError:
with_pos = None
if as_pos:
context_name = bits[as_pos+1]
else:
context_name = None
if with_pos:
if as_pos:
bargs = bits[with_pos+1:as_pos]
else:
bargs = bits[with_pos+1:]
else:
bargs = []
args = []
kwargs = {}
if bargs:
for barg in bargs:
t = barg.split('=')
if len(t) > 1:
kwargs[t[0]] = t[1]
else:
args.append(t[0])
return CallNode(object, method, args=args, kwargs=kwargs, context_name=context_name)
elif len(bits) == 2:
return CallNode(object, method)
else:
raise template.TemplateSyntaxError(syntax_message)