Python 支持白名单的模板替换?
是否可以使用Python 支持白名单的模板替换?,python,string,templates,Python,String,Templates,是否可以使用string.Template强制替换白名单中提到的一组变量($placeholder*)和跳过其余部分($data等) substitute为所有不存在的占位符抛出异常safe\u substitute忽略所有不存在的占位符——那么中间有什么东西吗 from string import Template whitelist = {"placeholder1", "placeholder2", "placeholder3"
string.Template
强制替换白名单中提到的一组变量($placeholder*
)和跳过其余部分($data
等)
substitute
为所有不存在的占位符抛出异常safe\u substitute
忽略所有不存在的占位符——那么中间有什么东西吗
from string import Template
whitelist = {"placeholder1", "placeholder2", "placeholder3", "placeholder4"}
query = Template("select * from t where c1= $data and c1 = $placeholder1 and c2 = $placeholder2")
print(query.safe_substitute({"placeholder1": "c1"})) # Not safe.
query.substitute({"placeholder1": "c1"}) # Extra safe.
最后,我可以通过循环白名单来进行验证,但这似乎效率低下。另外,我看不到有人支持这一点
如果没有好的解决方案,我是否可以将子类
模板
和重载替换为以下内容:
def substitute(self, mapping=_sentinel_dict, /, **kws, whitelist):
if mapping is _sentinel_dict:
mapping = kws
elif kws:
mapping = _ChainMap(kws, mapping)
# Helper function for .sub()
def convert(mo):
# Check the most common path first.
named = mo.group('named') or mo.group('braced')
if named is not None:
# ====> Suggested change. <====
if named in whitelist:
return str(mapping[named])
else:
return mo.group() # ====> Taken from safe_substitute.
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
self._invalid(mo)
raise ValueError('Unrecognized named group in pattern',
self.pattern)
return self.pattern.sub(convert, self.template)
def替换(self,映射=_sentinel_dict,/,**kws,白名单):
如果映射是_sentinel_dict:
映射=kws
elif kws:
映射=\链映射(kws,映射)
#.sub()的助手函数
def转换(mo):
#首先检查最常见的路径。
named=mo.group('named')或mo.group('bracked')
如果“命名”不是“无”:
#=>建议的更改。从保险箱中取出。
如果mo.group(‘转义’)不是无:
返回自分隔符
如果mo.group('invalid')不是无:
自身失效(mo)
raise VALUERROR('模式中无法识别的命名组',
自我评价(模式)
返回self.pattern.sub(转换,self.template)
我想说,您提议的实现几乎完美无瑕
- 首先,请注意,此实现不允许您执行类似于
MyTemplate(“$whitelist”).substitute(whitelist='a')
并因此获得'a'
(因为您不能为参数whitelist
传递多个值)
- 然后,如果在白名单中命名,则需要将
:return str(mapping[named])
更改为稍微复杂一点的内容。事实上,如果命名
不在白名单
中,而是属于映射
的一部分,那么您就无法正确处理这种情况。因此,您需要执行以下操作
以下是一个工作实现:
from collections import ChainMap
from string import Template
class MyTemplate(Template):
def substitute(self, mapping=None, whitelist=None, **kws):
mapping = kws if mapping is None else ChainMap(kws, mapping)
whitelist = {} if whitelist is None else whitelist
def convert(mo):
named = mo.group('named') or mo.group('braced')
if named is not None:
if named in mapping:
return str(mapping[named])
if named in whitelist:
raise KeyError(named)
return mo.group()
if mo.group('escaped') is not None:
return self.delimiter
if mo.group('invalid') is not None:
self._invalid(mo)
raise ValueError('Unrecognized named group in pattern', self.pattern)
return self.pattern.sub(convert, self.template)
以下是一些例子:
>>> whitelist = {'a', 'b'}
>>> temp = MyTemplate('Lorem $a $b sit ${c}')
>>> temp.substitute({'a': 'ipsum', 'b': 'dolor', 'c': 'amet'}, whitelist)
'Lorem ipsum dolor sit amet'
>>> temp.substitute({'a': 'ipsum', 'b': 'dolor'}, whitelist)
'Lorem ipsum dolor sit ${c}'
>>> temp.substitute({'a': 'ipsum', 'c': 'amet'})
'Lorem ipsum $b sit amet'
>>> temp.substitute({'a': 'ipsum', 'c': 'amet'}, whitelist)
...
KeyError: 'b'
子类化模板
(而不是实现另一个解决方案)的优点是,子类附带了模板
的所有其他功能(例如,您可以将分隔符“$”更改为其他内容,或者您可以定义自己的规则来标识占位符等).我想将白名单
保留为一个全局集
变量(或每个模板),但在提交问题时将其更改为一个参数。我会仔细看看。谢谢@Nishant的一个选项是在创建MyTemplate时将其传递给MyTemplate,但每次要更改白名单时都需要创建一个新的template对象。它实际上取决于您的需要,例如是白名单
常量还是随时间而变化?除非业务发生变化,否则它是常量:-)
>>> whitelist = {'a', 'b'}
>>> temp = MyTemplate('Lorem $a $b sit ${c}')
>>> temp.substitute({'a': 'ipsum', 'b': 'dolor', 'c': 'amet'}, whitelist)
'Lorem ipsum dolor sit amet'
>>> temp.substitute({'a': 'ipsum', 'b': 'dolor'}, whitelist)
'Lorem ipsum dolor sit ${c}'
>>> temp.substitute({'a': 'ipsum', 'c': 'amet'})
'Lorem ipsum $b sit amet'
>>> temp.substitute({'a': 'ipsum', 'c': 'amet'}, whitelist)
...
KeyError: 'b'