为 Django 模板定义 API?
Posted
技术标签:
【中文标题】为 Django 模板定义 API?【英文标题】:Define API for Django-Templates? 【发布时间】:2018-09-04 11:36:41 【问题描述】:我认为模板可以与方法相媲美。
IPO(输入-处理-输出):
-
需要一些输入。
它做了一些处理
它会输出一些东西。很可能是 html。
在 Python 中,方法具有必需参数和可选参数(具有默认值)。
有没有办法为 Django 模板定义(我称之为)API?
我需要一些参数。 我希望某些参数具有默认值。用例:客户可以通过 Web 界面编辑模板。我想告诉客户对模板的更改是否有效。
我可以渲染模板看看是否发生错误,但这不包括这种情况:
模板应呈现值“foo_needs_to_get_rendered”。
在这种情况下,通过渲染(并丢弃结果)验证模板不会显示错误。
相关:我想向编辑模板的客户显示帮助消息。我想列出上下文的所有可用变量。示例:“您可以使用这些变量:foo、bar、blue ...”
【问题讨论】:
好主意!我希望你能分享结果。 @albar 感谢您的积极反馈! ....我喜欢投票:-) 这更像是设计问题,而不是代码。因为会有不同的方式来实现这样的系统。那么您在这里有确切的查询吗? 您可以设置错误类型的默认值以在渲染时引发错误,然后捕获这些错误以向用户提供洞察力 好一个。类似于 Smart Wysiwyg 的东西? 【参考方案1】:Django 模板首先在Context
对象(这是一种字典)中查找键。如果密钥不存在,KeyError
会被模板引擎捕获。通常,密钥将呈现为空白。
所以在我看来,如果你想绕过这种行为,你需要让一个丢失的键引发除 KeyError 之外的其他东西。或者,您可以在模板引擎之前捕获KeyError
,并在重新引发之前保存该信息。
您可以通过子类化Context
来做到这一点,这需要对模板引擎代码进行一些研究......但这可能是一个非常好的方法。但是您也可以将您的 API 包装在一个执行此操作的特殊类中......并将其放在上下文中。以下代码尚未经过测试.. 将其视为伪代码,您可以将其用作起点...
# our own KeyError class that won't be caught by django
class APIKeyError(Exception):
pass
class API(object):
def __init__(self, context, exc_class=APIKeyError):
self.context = context
self.exc_class = exc_class
self.invalid_keys = set()
self.used_keys = set()
@property
def unused_keys(self):
return set(self.context.keys()) - self.used_keys
def __getattr__(self, name):
try:
value = self.context.get(name)
self.used_keys.add(name)
return value
except KeyError:
self.invalid_keys.add(name)
if self.exc_class is None:
raise
raise self.exc_class(
'API key "%s" is not valid. Available keys are %s.' %
(name, self.context.keys()))
那么你会像这样检查你的模板:
from django.template.loader import render_to_string
api = API(
'foo': 'foovalue',
'bar': 'barvalue',
'baz': 'bazvalue',
, None)
render_to_string('template.html', 'api': api , request=request)
# now the API class instance knows something about the keys (only within
# the 'api' namespace that the template used...
print api.used_keys # set of keys that the template accessed that were valid
print api.invalid_keys # set of keys the template accessed that were invalid
print api.unused_keys # set of keys valid keys that were not used
现在,请注意,如果您不想在最后进行任何检查,但只在用户使用无效密钥时抛出异常,请不要将 None
传递为 exc_class
,它会当模板中有错误的 api.key 时抛出 APIKeyError
。
所以,希望这会给你一些想法和一些代码的起点。正如我所说,这根本没有经过测试。把它当作伪代码。
当然,这只会保护 API 中的密钥。任何不以 api
开头的密钥对于 Django 来说都是正常的。但这里的优点是您只使用自己的代码,而不是暴露于对 Django 未来版本的更改的破坏。
【讨论】:
逻辑有问题,未将使用的键添加到列表中,我已修复。【参考方案2】:它做 IPO(输入-处理-输出):
刚开始学Django的时候我也有同样的想法。以下是我当时每个模板的第一行。最初的目的是在我想调试模板时显示输入值,方法是删除第一行中的% comment %
。
# This comment is to let vim know this is django html template. #% comment %
Purpose: Generate inline add form for intercoolerjs to update single page view.
Input: show_add_form: show_add_form , list_path: list_path , detail_id: detail_id % if show_add_form %, default_desc: default_desc % else %% endif %
% comment %% endcomment %
所以对于定义 API,我认为我们可以从这个模板头之类的东西开始。然后,您的代码可以在生成的模板中查找 doc_string 和 ValueError。
% comment %
doc_string: You can use these variables: foo, bar, blue (default is yellow) ..
% comment %% endcomment %
% load my_tags %
% required foo 'foo_needs_to_get_rendered' %
% required bar 'bar_needs_to_get_rendered' %
% set_with_default blue 'yellow' as blue %
set_with_default
和 required
是 custom tags 中的 <your app>/templatetags/my_tags.py
per document。
from django import template
register = template.Library()
@register.simple_tag
def set_with_default(value, default=''):
if value:
pass
else:
return default
return value
@register.simple_tag
def required(value, message):
if value:
pass
else:
return 'ValueError: "%s"' % message
return ''
【讨论】:
我刚刚添加了required
标签以在变量丢失时显示消息。尚不知道如何获取值的名称以避免在消息中对其进行硬编码。以上是关于为 Django 模板定义 API?的主要内容,如果未能解决你的问题,请参考以下文章