我有一个配置文件,其中特定设置需要一个长丑陋的json样式字典。我想在YAML中定义这个字典并用Jinja打印出来。目前看起来像这样:
{%- load_yaml as some_conf_val %}
val1: something
val2: completely
val3: different
{%- endload %}
option = {{ some_conf_val }}
# Results in:
option = {'val2': 'completely', 'val1': 'something', 'val3': 'different'}
幸运的是,这正是所配置程序所期望的格式,并且yaml块比内联版本更容易阅读和修改。但是,密钥既不按字母顺序排列,也不按定义顺序排列,这使我怀疑它们的输出顺序是非确定性的。在重新运行状态几次时,它们总是以相同的顺序出现,但这并不能证明这一点。
这是一个问题,因为如果输出字符串被更改,它将被视为对文件的更改并触发服务重新启动,即使没有任何功能已更改。我并不关心密钥的具体顺序,但我确实每次都需要这个顺序。
我怎样才能做到这一点?或者它是否已经确定,并且看起来不像?
(如果我理解正确,jinja dicts真的是python dicts,并且python dicts是无序的,所以如果没有包含比我试图没有的代码更麻烦的代码,这可能是不可能的。写作。但我不希望。)
答案 0 :(得分:1)
你是对的,Python的标准字典是无序的。 collections
模块中有一个有序版本:collections.OrderedDict
。我们可以使用定制的Jinja2过滤器将其用于此目的。
自定义过滤器首先将输入转换为OrderedDict,然后转换为JSON,最后替换双引号:
from json import dumps
from collections import OrderedDict
def conffilter(value):
return dumps(OrderedDict(value)).replace('"', '\'')
然后我们必须add this new filter到Jinja2:
env.filters['conffilter'] = conffilter
其中env
是您应用中的Jinja2 Environment
对象(例如,在Flask中它是app.jinja_env
)。
现在我们可以将新过滤器与Jinja2的dictsort
过滤器一起使用。
# Define a list for testing:
{%- set some_conf_val = {'val2': 'completely', 'val1': 'something', 'val3': 'different'} -%}
# Unordered dict output
option = {{ some_conf_val }}
# Result:
option = {'val1': 'something', 'val3': 'different', 'val2': 'completely'}
# Ordered list of tuples
option = {{ some_conf_val|dictsort }}
# Result:
option = [('val1', 'something'), ('val2', 'completely'), ('val3', 'different')]
# Ordered dict-like output:
option = {{ some_conf_val|dictsort|conffilter }}
# Result:
option = {'val1': 'something', 'val2': 'completely', 'val3': 'different'}
答案 1 :(得分:1)
事实证明,saltstack为json输出提供了一个过滤器,可以对其键进行排序,并可以按摩以获得我想要的效果。我最终使用的解决方案如下所示:
option = {{ some_conf_val|json|replace('"', "'") }}
# Results in:
option = {'val1': 'something', 'val2': 'completely', 'val3': 'different'}
替换操作是因为该选项最终被提供给关心它所关注的引用的东西。它可能不适用于其他情况。
据我所知,排序行为尚未记录,但您可以在源here中找到它。