Jinja: تجاوز autoescape

تم إنشاؤها على ١٥ أكتوبر ٢٠١٥  ·  11تعليقات  ·  مصدر: pallets/jinja

في العمل ، نستخدم Jinja لتقديم القوالب كـ YAML. نود تخصيص جميع توسعات {{ variable }} للقيام بشيء معقول لقيم Python مثل None (وهو null في YAML) وسلسلة فارغة (التي تم ترميزها كـ '' في YAML). يبدو أن آلية Jinja autoescaping ستكون مثالية لهذا الغرض. لسوء الحظ ، لا أرى أي طريقة لتكوين وظيفة autoescaping لعدم الانتقال التلقائي إلى HTML. بدلاً من ذلك ، اضطررت إلى monkeypatch Markup و escape في jinja2.runtime . سيكون من الجيد لو كانت هناك طريقة معتمدة رسميًا للقيام بذلك ، على سبيل المثال عن طريق تجاوز شيء ما في البيئة.

ال 11 كومينتر

لست متأكدًا مما إذا كانت عملية النسخ التلقائي هي الطريقة الصحيحة للقيام بذلك.

أفضل استخدام مرشح. tojson مرشحًا جيدًا لأن yaml هي مجموعة شاملة من json.


بالإضافة إلى ذلك: أي سبب لماذا تقوم بإنشاء قوالب مستندة إلى سلسلة لبناء YAML؟ يبدو تحويل قاموس Python كـ YAML أكثر نظافة. الحالة الوحيدة التي يمكنني أن أرى فيها حيث قد لا يكون هذا كافيًا هي عندما تريد تضمين التعليقات. ولكن في هذه الحالة ، يمكنك استخدام محرك YAML الذي يتعامل مع القراءة / الكتابة غير المدمرة ، لذا يمكنك ببساطة تحميل قالب YAML مع تعليقاتك والعناصر الفارغة ثم تحديث البيانات وإعادة تسلسلها كـ YAML.

الهدف من استخدام autoescaping هو أنني لا أريد أن أضطر إلى وضع مرشح على كل توسع متغير واحد.

حالة الاستخدام لدينا هي كتابة ملفات التكوين لخدماتنا المصغرة. لدينا "نموذج" مضمن مع كل خدمة ونريد ملئه بالتهيئة الخاصة بكل بيئة والتي تخص هذا القالب. أوافق على أن استخدام YAML بشكل مباشر أكثر نظافة ، لكن لم نتمكن من العثور على "محرك" عام يعرف كيفية استبدال المتغيرات التي لا يعرف موقعها بالفعل. (هناك مراجع وأسماء مستعارة لـ YAML ، لكنها ليست مناسبة تمامًا لذلك - إنها أكثر لتسلسل الهياكل الدورية.) هناك طرق يمكنني التفكير فيها لجعل هذا يعمل باستخدام YAML ، لكنها نوع من الاختراق أيضًا. يمنح هذا الإعداد أيضًا مزيدًا من التحكم في أنواع الاستبدالات التي يمكننا إجراؤها ، على الرغم من أننا في الممارسة العملية لا نستخدم ذلك حقًا لأي شيء.

يمكنك استخدام jinja plugin لتطبيق المرشح على جميع المتغيرات. ليس الأمر صعبًا طالما أنك لست مضطرًا لاستخدام كتل i18n. ربما يمكنك أخذ بعض الأفكار من شيء كتبته منذ بعض الوقت: https://github.com/indico/indico/blob/master/indico/web/flask/templating.py#L187

هذا مفيد جدا ، شكرا! أشعر أن أسلوب autoescaping لا يزال طريقة جيدة لحل هذا الأمر لأنه يمكنك على سبيل المثال وضع علامة على المتغيرات كـ |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 ، وأريد استخدام JSON escaping بدلاً من HTML escaping.

يعد استخدام قوالب Jinja أو أي لغة قالب أو عمليات سلسلة أخرى مستندة إلى سلسلة على الإطلاق لإنشاء JSON أمرًا خاطئًا. أستطيع أن أرى سبب قيامك بهذا من أجل YAML لأنه من المفترض أن يكون صديقًا للإنسان أيضًا ، ولكن يجب إنشاء JSON من مثال Pythonمة وليس من قالب Jinja.

(مع ذلك ، لدي فضول لماذا تريد القيام بذلك وماذا تحاول القيام به: p)

أعتقد أن من المنطقي. :-) سأغلق # 571.

ربما لا يكون إنشاء JSON جيدًا بواسطة Jinja ، لكنني مهتم جدًا بهذا النوع من الميزات لأنني أقوم بإنشاء LaTeX باستخدام jinja. لقد نجحت في تحقيق ذلك من خلال تعديل block_start_string و block_end_string وغيرها في Environment . في الوقت الحالي ، قمت بتعيين autoescape = False ، لكن من الناحية المثالية أرغب في تمرير شيء ما للقيام بالهروب بنفسي (ربما مثل regex).

ينطبق هذا أيضًا على إنشاء نص عادي وتخفيض السعر. لقد كانت Jinja أداة رائعة حتى الآن لنمذجة المستندات التي ليست بتنسيق html.

كنت أبحث في استخدام jinja لإنشاء استعلامات SQL لأن استخدام str.format() يمكن أن يصبح فوضويًا إذا كنت بحاجة إلى أجزاء استعلام شرطية متعددة.

توجد بالفعل مكتبات للقيام بذلك ، وهي jinja-vanish التي تسمح بوظائف الهروب المخصصة و jinjasql .
يجب على الأول تعطيل التقييم المستمر في الترجمة والذي يبدو سيئًا بعض الشيء. الآخر
يستخدم مرشح aproach لإضافة مرشح خاص لجميع تعبيرات المتغيرات التي لا بأس بها ولكنها أيضًا غير صحيحة.

لم أتعمق في الأمر ولكن لا يبدو أن تنفيذه بهذه الصعوبة. هل يمكن النظر في هذا أم أنه خارج نطاق المكتبة؟

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات