์ง์ฅ์์ ์ฐ๋ฆฌ๋ ํ
ํ๋ฆฟ์ YAML๋ก ๋ ๋๋งํ๊ธฐ ์ํด Jinja๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ๋ชจ๋ {{ variable }}
ํ์ฅ์ ์ฌ์ฉ์ ์ ์ํ์ฌ None
(YAML์์ null
์) ๋ฐ ๋น ๋ฌธ์์ด( ''
๋ก ์ธ์ฝ๋ฉ๋จ)๊ณผ ๊ฐ์ Python ๊ฐ์ ์ ํฉํ ์์
์ ์ํํ๊ณ ์ถ์ต๋๋ค ''
). Jinja ์๋ ์ด์ค์ผ์ดํ ๋ฉ์ปค๋์ฆ์ด ์ด์ ์ ํฉํ ๊ฒ ๊ฐ์ต๋๋ค. ๋ถํํ๋ HTML๋ก ์๋ ์ด์ค์ผ์ดํํ์ง ์๋๋ก ์๋ ์ด์ค์ผ์ดํ ๊ธฐ๋ฅ์ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋์ ์, ๋๋ monkeypatch ํ์ด Markup
๋ฐ escape
์ jinja2.runtime
. ์๋ฅผ ๋ค์ด ํ๊ฒฝ์์ ๋ฌด์ธ๊ฐ๋ฅผ ์ฌ์ ์ํ๋ ๊ฒ๊ณผ ๊ฐ์ด ๊ณต์์ ์ผ๋ก ์น์ธ๋ ๋ฐฉ๋ฒ์ด ์์ผ๋ฉด ์ข์ ๊ฒ์
๋๋ค.
์๋ ์ด์ค์ผ์ดํ๊ฐ ์ด๋ฅผ ์ํํ๋ ์ ์ ํ ๋ฐฉ๋ฒ์ธ์ง ํ์คํ์ง ์์ต๋๋ค.
ํํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. tojson
๋ yaml์ด json์ ์์ ์งํฉ์ด๊ธฐ ๋๋ฌธ์ ์ข์ ํ๋ณด๋ก ๋ณด์
๋๋ค.
๊ทธ ์ธ์๋ YAML์ ๋น๋ํ๊ธฐ ์ํด ๋ฌธ์์ด ๊ธฐ๋ฐ ํ ํ๋ฆฟ์ ์ฌ์ฉํ๋ ์ด์ ๊ฐ ์์ต๋๊น? Python ์ฌ์ ์ YAML๋ก ์ง๋ ฌํํ๋ ๊ฒ์ด ํจ์ฌ ๊น๋ํด ๋ณด์ ๋๋ค. ์ด๊ฒ์ด ์ถฉ๋ถํ์ง ์์ ์ ์๋ ์ ์ผํ ๊ฒฝ์ฐ๋ ์ฃผ์์ ํฌํจํ๋ ค๋ ๊ฒฝ์ฐ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ด ๊ฒฝ์ฐ ๋นํ๊ดด์ ์ฝ๊ธฐ/์ฐ๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๋ YAML ์์ง์ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ์ฃผ์๊ณผ ๋น ํญ๋ชฉ์ด ์๋ YAML ํ ํ๋ฆฟ์ ๋ก๋ํ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธํ๊ณ YAML๋ก ๋ค์ ์ง๋ ฌํํ๋ฉด ๋ฉ๋๋ค.
์๋ ์ด์ค์ผ์ดํ๋ฅผ ์ฌ์ฉํ๋ ์์ ์ ๋ชจ๋ ๋จ์ผ ๋ณ์ ํ์ฅ์ ํํฐ๋ฅผ ์ ์ฉํ๊ณ ์ถ์ง ์๋ค๋ ๊ฒ์ ๋๋ค.
์ฐ๋ฆฌ์ ์ฌ์ฉ ์ฌ๋ก๋ ๋ง์ดํฌ๋ก ์๋น์ค์ ๋ํ ๊ตฌ์ฑ ํ์ผ์ ์์ฑํ๋ ๊ฒ์ ๋๋ค. ๊ฐ ์๋น์ค์ ํฌํจ๋ "ํ ํ๋ฆฟ"์ด ์์ผ๋ฉฐ ํด๋น ํ ํ๋ฆฟ์ ํน์ ํ ํ๊ฒฝ๋ณ ๊ตฌ์ฑ์ผ๋ก ์ฑ์ฐ๊ณ ์ถ์ต๋๋ค. ๋๋ YAML์ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ๊นจ๋ํ๋ค๋ ๋ฐ ๋์ํ์ง๋ง ์์ง ์์น๋ฅผ ์์ง ๋ชปํ๋ ๋ณ์๋ฅผ ๋์ฒดํ๋ ๋ฐฉ๋ฒ์ ์๊ณ ์๋ ์ผ๋ฐ "์์ง"์ ์ฐพ์ ์ ์์ต๋๋ค. (YAML ๋ณ์นญ๊ณผ ์ฐธ์กฐ๊ฐ ์์ง๋ง ์ค์ ๋ก๋ ์ ํฉํ์ง ์์ต๋๋ค. ์ํ ๊ตฌ์กฐ๋ฅผ ์ง๋ ฌํํ๋ ๋ฐ ๋ ์ ํฉํฉ๋๋ค.) YAML์ ์ฌ์ฉํ์ฌ ์ด๊ฒ์ ์๋ํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ ์ ์์ง๋ง, ์ผ์ข ์ ํดํค๋. ์ด ์ค์ ์ ๋ํ ์ฐ๋ฆฌ๊ฐ ์ํํ ์ ์๋ ๋์ฒด ์ ํ์ ๋ํ ๋ ๋ง์ ์ ์ด๋ฅผ ์ ๊ณตํ์ง๋ง ์ค์ ๋ก๋ ์ค์ ๋ก ์ด๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.
jinja ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ๋ณ์์ ํํฐ๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค. i18n ๋ธ๋ก์ ์ฌ์ฉํ ํ์๊ฐ ์๋ค๋ฉด ๊ทธ๋ ๊ฒ ์ด๋ ต์ง ์์ต๋๋ค. ๋ด๊ฐ ์ผ๋ง ์ ์ ์์ฑํ ๊ฒ์์ ์์ด๋์ด๋ฅผ ์ป์ ์ ์์ต๋๋ค. https://github.com/indico/indico/blob/master/indico/web/flask/templating.py#L187
์ด๊ฒ์ ๋งค์ฐ ๋์์ด ๋ฉ๋๋ค. ๊ฐ์ฌํฉ๋๋ค! ์๋ฅผ ๋ค์ด ๋ณ์์ |safe
ํ๋๊ทธ๋ฅผ ์ง์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ์๋ ์ด์ค์ผ์ดํ๊ฐ ์ฌ์ ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๊ด์ฐฎ์ ์ ๊ทผ ๋ฐฉ์์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ๋
์ ์ผ๋ก ์ด๊ฒ์ ์๋ ์ด์ค์ผ์ดํ์ ๊ฐ์ง ์๋ค๋ ์ ์ ์ธ์ ํฉ๋๋ค. ๋ณ์๊ฐ ์ ํจํ YAML์ธ์ง ํ์ธํ๋ ๊ฒ์ด ์๋๋ผ ํน์ ๋ฐฉ์์ผ๋ก ํ์์ ์ง์ ํ๊ธฐ ๋๋ฌธ์
๋๋ค. ํ์ฅ์๋ฅผ ์ฐ๊ฒ ์ต๋๋ค.
@glasserc ์ด ํ์ฅ์ผ๋ก ์ฑ๊ณตํ์ จ๋์? ๋น์ทํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ํด๊ฒฐ์ฑ ์ ์ง์ ํ๊ฑฐ๋ ๋ช ๊ฐ์ง ์์ด๋์ด๋ฅผ ๊ณต์ ํ ์ ์์ต๋๊น?
๋ด ์๋ฃจ์ ์ ์ฒซ ๋ฒ์งธ ๋ถ๋ถ์ ํํฐ๋ฅผ ํตํด ๋ชจ๋ ๋ณ์ ํธ์ถ์ ์คํํ๋ ํ์ฅ์ด์์ต๋๋ค. ์ด๊ฒ์ด ๋ด๊ฐ ์์ ์ ์ํํ๋ ๋ฐ ํ์ํ ์ต์ํ์ ๊ฒ์ ๋๋ค.
import jinja2.ext
from jinja2.lexer import Token
class YAMLEverythingExtension(jinja2.ext.Extension):
"""
Insert a `|yaml` filter at the end of every variable substitution.
This will ensure that all injected values are converted to YAML.
"""
def filter_stream(self, stream):
# This is based on https://github.com/indico/indico/blob/master/indico/web/flask/templating.py.
for token in stream:
if token.type == 'variable_end':
yield Token(token.lineno, 'pipe', '|')
yield Token(token.lineno, 'name', 'yaml')
yield token
์๋ฅผ ๋ค์ด ๋ณ์ ๋ธ๋ก์ ๋ช
์์ ์ผ๋ก safe
๋๋ yaml
ํํฐ๊ฐ ์๋ ๊ฒฝ์ฐ ํํฐ ์ฝ์
์ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ ๊ฒฐ์ฝ ๊ทธ๊ฒ์ ์ํ ์๊ฐ์ ํ์๋ก/๊ฐ์ง๋ ๊ฒ์ ๋๋ด์ง ๋ชปํ์ต๋๋ค.
๋ ๋ฒ์งธ ๋ถ๋ถ์ ํํฐ ์์ฒด์
๋๋ค. yaml.dump
์ฌ์ฉํ๋ ๊ฒ๋ง์ผ๋ก๋ ์ถฉ๋ถํ ์ ๊ตํ์ง ์์๊ธฐ ๋๋ฌธ์ yaml ๋ด๋ถ๋ฅผ ์ฝ๊ฐ ์ฐ๋ฌ์ผ ํ์ต๋๋ค.
import cStringIO
import yaml
def yaml_filter(val):
"""Serialize some value in isolation, not as part of any document.
We can't just use yaml.dump because that outputs an entire document, including newlines, which isn't helpful for
inserting into a YAML document."""
if isinstance(val, jinja2.Undefined):
val._fail_with_undefined_error()
stream = cStringIO.StringIO()
dumper = yaml.dumper.Dumper(stream)
dumper.open()
node = dumper.represent_data(val)
dumper.serialize(node)
# The serialized node tends to have a \n at the end. The template might not
# want a \n inserted here, e.g. if two variables are on the same line, so
# strip.
return stream.getvalue().strip()
์ด๊ฒ์ ์ฃผ์ด์ง ์ด๋ฆ์ ํํฐ๊ฐ ํ๊ฒฝ์์ ์ฌ์ฉ ๊ฐ๋ฅํ์ง ํ์ธํ๋ ๊ฒ์ ํฌํจํ์ฌ ๋ชจ๋ ๊ฒ์ ํ๋๋ก ๋ฌถ์ต๋๋ค.
from jinja2 import loaders
from jinja2 import Environment, StrictUndefined
def get_environment():
"""Create a standard Jinja environment that has everything in it.
"""
jinja_env = Environment(extensions=(YAMLEverythingExtension,),
# some other options that we use at work
loader=loaders.FileSystemLoader(['.', '/']),
undefined=StrictUndefined)
jinja_env.filters["yaml"] = yaml_filter
return jinja_env
์ด๊ฒ์ HTML์ด ์๋ ํ ํ๋ฆฟ์ ์ด์ค์ผ์ดํํ๋ ๋ฐ ์ฌ์ ํ ์ ์ฉํฉ๋๋ค. Jinja2๋ฅผ ์ฌ์ฉํ์ฌ JSON์ ์์ฑํ๊ณ HTML ์ด์ค์ผ์ดํ ๋์ JSON ์ด์ค์ผ์ดํ๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ต๋๋ค.
JSON์ ์์ฑํ๊ธฐ ์ํด Jinja ํ ํ๋ฆฟ ๋๋ ๊ธฐํ ๋ฌธ์์ด ๊ธฐ๋ฐ ํ ํ๋ฆฟ ์ธ์ด ๋๋ ๋ฌธ์์ด ์์ ์ ์ฌ์ฉํ๋ ๊ฒ์ ์๋ชป๋ ๊ฒ์ ๋๋ค. YAML๋ ์ธ๊ฐ ์นํ์ ์ด๊ธฐ ๋๋ฌธ์ YAML์ ๋ํด ์ด๋ ๊ฒ ํ๋ ์ด์ ๋ฅผ ์ ์ ์์ง๋ง JSON์ ์๋ฅผ ๋ค์ด Jinja ํ ํ๋ฆฟ์ด ์๋๋ผ Python dict์์ ์์ฑ๋์ด์ผ ํฉ๋๋ค.
(๊ทธ๋ฐ๋ฐ ์ ํ๊ณ ์ถ์์ง, ๋ฌด์์ ํ๋ ค๊ณ ํ๋์ง ๊ถ๊ธํฉ๋๋ค :p)
๊ทธ๊ฒ ๋ง์ด ๋๋ ๊ฒ ๊ฐ์์. :-) ๋๋ #571์ ๋ซ์ ๊ฒ์ด๋ค.
JSON์ Jinja์์ ์์ฑํ๋ ๊ฒ์ด ์ข์ง ์์ ์๋ ์์ง๋ง jinja๋ฅผ ์ฌ์ฉํ์ฌ LaTeX๋ฅผ ์์ฑํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ์ข
๋ฅ์ ๊ธฐ๋ฅ์ ๋งค์ฐ ๊ด์ฌ์ด ์์ต๋๋ค. block_start_string
๋ฐ block_end_string
๋ฐ ๊ธฐํ Environment
๋ฅผ ์์ ํ์ฌ ๋๋ถ๋ถ์ ๋ฐฉ๋ฒ์ ์ป์์ต๋๋ค. ์ง๊ธ์ autoescape = False
๋ฅผ ์ค์ ํ์ง๋ง ์ด์์ ์ผ๋ก๋ ์์ ์ ํ์ถํ๊ธฐ ์ํด ๋ฌด์ธ๊ฐ๋ฅผ ์ ๋ฌํ๊ณ ์ถ์ต๋๋ค(์ ๊ท์์ฒ๋ผ).
์ด๋ ์ผ๋ฐ ํ ์คํธ ๋ฐ ๋งํฌ๋ค์ด ์์ฑ์๋ ์ ์ฉ๋ฉ๋๋ค. Jinja๋ ์ง๊ธ๊น์ง ๋น-html ๋ฌธ์๋ฅผ ํ ํ๋ฆฟํํ๋ ํ๋ฅญํ ๋๊ตฌ์์ต๋๋ค.
์ฌ๋ฌ ์กฐ๊ฑด๋ถ ์ฟผ๋ฆฌ ๋ถ๋ถ์ด ํ์ํ ๊ฒฝ์ฐ str.format()
๋ฅผ ์ฌ์ฉํ๋ฉด ์ง์ ๋ถํด์ง ์ ์๊ธฐ ๋๋ฌธ์ jinja๋ฅผ ์ฌ์ฉํ์ฌ SQL ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์ฐพ๊ณ ์์์ต๋๋ค.
์ด๋ฅผ ์ํํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์ฆ ์ฌ์ฉ์ ์ ์ ์ด์ค์ผ์ดํ ๊ธฐ๋ฅ๊ณผ jinjasql ์ ํ์ฉํ๋ jinja-vanish ๊ฐ ์ด๋ฏธ ์์ต๋๋ค.
์ฒซ ๋ฒ์งธ๋ ์ปดํ์ผ ์ ์์ ํ๊ฐ๋ฅผ ๋นํ์ฑํํด์ผ ํ๋๋ฐ, ์ด๋ ์ฝ๊ฐ ์ข์ง ์์ต๋๋ค. ๋ค๋ฅธ ํ๋
ํํฐ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ์ฌ ๋ชจ๋ ๋ณ์ ํํ์์ ๊ด์ฐฎ์ง๋ง ์ณ์ง ์๋ค๊ณ ๋๋ผ๋ ํน์ ํํฐ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
์์ธํ ๋ค์ฌ๋ค๋ณด์ง๋ ์์์ง๋ง ๊ตฌํํ๋ ๊ฒ์ ๊ทธ๋ฆฌ ์ด๋ ต์ง ์์ ๊ฒ ๊ฐ์ต๋๋ค. ์ด๊ฒ์ด ๊ณ ๋ ค๋ ์ ์๊ฑฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฒ์๋ฅผ ๋ฒ์ด๋ฌ์ต๋๊น?