Drei nicht offensichtliche Beispiele für die Verwendung von Template-Engines im Backend

Einerseits war das Thema tatsächlich quadratisch. Auf der anderen Seite war es rund. Aber auf der dritten Seite, mit der das Dreieck sein sollte, kam das Objekt gekrümmt und schräg heraus.


- Geht Aljoschenka in den Besprechungsraum? - Lenochkina steckte in der Tür interessiertes Gesicht.
- Aljoschenka nimmt nicht an dem Treffen teil. Aleshenka schreibt einen Artikel.
- Über die Würfel?
- Welche anderen Würfel? - Ich senkte meine Augen in meinen Händen und die Wahrheit war ein unglücklicher Würfel. Das ist ein Ball. Das ist eine Raute.
- Nicht über Würfel! Und nicht über Bälle. Über Vorlagen.
"Das werde ich ihnen sagen!" Muster, ah. - Helen rannte bereits den Korridor entlang.


"Über Vorlagen. Sogar über drei verschiedene Vorlagen." Genauer gesagt, drei Gründe für die Verwendung von Vorlagen im Servercode. Und keiner dieser Gründe betrifft HTML.


In den Beispielen habe ich die Schnurrbart- Syntax verwendet, aufgrund der lakonischen Syntax und des Vorhandenseins von Implementierungen für alles, was sich bewegt. Moustache erlaubt sich praktisch keine Freiheiten, im Gegensatz zu beispielsweise .Net Razor, mit dem Sie in einer Vorlage codieren können, wodurch ein schlechtes Beispiel für schwache Entwickler gesetzt wird.


Codebeispiele werden in Python sein. Die Implementierung von Moustache for Python heißt Pystache .


Also drei Gründe, Muster hereinzulassen dein Leben Ihr Code.


Textartefakte


Wenn Sie ein System haben, in dem einige Daten vorhanden sind, z. B. Daten in einer relationalen Datenbank oder Daten, die durch API-Aufrufe abgerufen wurden, müssen Sie manchmal Artefakte basierend auf diesen Daten erstellen.


Das Artefakt kann beispielsweise eine JSON- oder Nur-Text-Datei, ein Anhang oder eine HTTP-Antwort sein. Die Hauptsache - ein Artefakt ist im Wesentlichen das Ergebnis der Anwendung einer Funktion aus einem relativ kompakten Teil der Daten in Ihrem System. Und das Artefakt hat eine eigene Syntax.


Das Artefakt kann ein Kontoauszug im Textformat zum Hochladen in das Altsystem sein. Das Artefakt kann das Entladen eines elektronischen Schecks in Form einer .json-Datei sein, die als Anhang per Post an den Kunden gesendet wird.


In all diesen Fällen vereinfachen Sie Ihr Leben erheblich, indem Sie Artefaktvorlagen verwenden.


Was ist eine Template-Engine? Dies ist eine Bibliothek, die ein Objektmodell (Kontext) verwendet, eine Vorlage erstellt, eine auf eine andere anwendet - und das Ergebnis angibt. Das Objektmodell und die Vorlage werden vom Programmierer vorbereitet. Das Endergebnis wird von der Template-Engine vorbereitet.


Beispiel: Versuchen Sie, eine Textnachricht über die Bestellung zu erstellen.


Bereiten Sie zunächst das Objektmodell vor:


def add_comma(list): for a in list[:-1]: a["comma"] = True def get_model(): res = { "documentId": 3323223, "checkDate": "01.02.2019 22:20", "posId": 34399, "posAddr": "Urupinsk, 1 Maya 1", "lines": [ { "no": 1, "itemtext": "Hello Kitty", "amount": 3, "sumRub": "55.20" }, { "no": 2, "itemtext": "Paper pokemons", "amount": 1, "sumRub": "1230.00" }, { "no": 2, "itemtext": "Book of Mustache", "amount": 1, "sumRub": "1000.00" } ], "total": { "amount": "3285.20" } } add_comma(res["lines"]) res["posInUrupinsk"] = res["posId"] > 34000 return res 

Der Code ist rein dumm. Im realen Code kann es eine Datenbankabfrage geben, eine Art Logik zum Berechnen von Werten (zum Beispiel berechnen wir den Wert von total.amount basierend auf Auftragspositionen).


Achten Sie auf einige Dinge:


  • Dies ist KEIN Objektmodell der Bestellung, sondern etwas Einfacheres, das für die Verwendung in der Vorlage vorbereitet wurde. Die Werte "sumRub" und "total.amount" im realen Geschäftsmodell sollten nicht textuell sein, der "Komma" -Wert des Zeilenarrays im Objektmodell gehört nicht dazu, es muss nur das Rendern vereinfacht werden (Pystache kann sich nicht verstehen, dass das Listenelement das letzte ist und danach muss kein Komma mehr gesetzt werden.
  • Der Feldtyp "Betrag" ist der Text und dieser Text ist für die Ausgabe in der Vorlage formatiert. Wenn Ihre Template-Engine Formatierer unterstützt (etwa "... {someValue | asMoney}"), ist eine Formatierung direkt im Modell nicht erforderlich.
  • Der Text in der Vorlage sollte für Kunden aus Uryupinsk etwas anders aussehen (der Manager lief im letzten Moment hoch und bat um Hinzufügung - das Unternehmen fragte wirklich, sie starteten plötzlich eine Marketingkampagne für die Stadt). Daher haben wir dem Modell den booleschen Wert "posInUrupinsk" hinzugefügt und in der Vorlage verwendet.
  • Es ist besser, das Modell nicht erneut aus der Vorlage zu verwenden, außer zum Rendern anderer Vorlagen

Der Text der Schnurrbartvorlage sieht folgendermaßen aus:


 {{#posInUrupinsk}}    !        100   . {{/posInUrupinsk}} {{^posInUrupinsk}}    : {{/posInUrupinsk}} {{#lines}} #{{no}} ... {{itemtext}}: {{sumRub}} {{#comma}};{{/comma}}{{^comma}}.{{/comma}} {{/lines}} : {{total.amount}} --------------------------- N : {{documentId}}  {{checkDate}} 

In der Vorlage sehen wir, dass sich der Belegkopf für Bestellungen in Uryupinsk von anderen Städten unterscheidet. Wir sehen auch, dass am Ende der letzten Zeile mit der Warenposition ein Punkt steht und in allen frühen Positionen ein Semikolon. Verantwortlich dafür sind das Attribut "comma" und die Methode "add_comma" im Modellgenerator.


Der Code, der den Kontext auf die Vorlage anwendet, ist trivial:


 model = get_model() with open(os.path.join("templates", "check.txt.mustache"), 'r') as f: template = f.read() check_text = pystache.render(template, model) print(check_text) 

Ergebnis:


    !        100   . #1 ... Hello Kitty: 55.20 ; #2 ... Paper pokemons: 1230.00 ; #2 ... Book of Mustache: 1000.00 . : 3285.20 --------------------------- N : 3323223  01.02.2019 22:20 

Ein weiterer Tipp: Wenn die Aufgabe dies zulässt, speichern Sie das Modell selbst mit der gerenderten Vorlage (z. B. im JSON-Format). Dies hilft beim Debuggen und bei der Fehlerbehebung.




Der Drucker quietschte dreimal und gab ein neues Modell heraus. Die dreieckige Seite war jetzt ein perfektes Dreieck. Die anderen beiden Seiten waren quadratisch. Das neuronale Netzwerk lebte sein eigenes Leben und weigerte sich, in jeder Hinsicht ein primitives Modellmodell herauszugeben.


"Ich werde Helen einen Würfel geben." Dachte ich. Lass es sich freuen.


Codegenerierung


Möglicherweise müssen Sie zur Laufzeit JavaScript im Backend erstellen. Warum? Zum Beispiel zum Erstellen von Berichten auf der Browserseite. Oder holen Sie sich ein Skript in F # aus einem Go-Programm. Oder der Kotlin-Code aus ReactJS (ich kann mir nicht vorstellen, warum dies notwendig sein könnte, aber plötzlich haben Sie solche spezifischen Neigungen).


Bei der Codegenerierung ist es besser, zuerst den resultierenden Code (den wir generieren möchten) mit Ihren Händen zu schreiben und ihn dann in eine Vorlage und ein Modell zu zerlegen. Dieser Ansatz wird uns retten Sehnsucht übermäßige Komplexität des Modells. Es ist nie zu spät, ein Modell zu komplizieren, aber es ist am besten, mit einem einfachen zu beginnen.


 var report = CreateChart({ title: "   - " }, type: "lineChart", sourceUrl: "/reports/data/0" ); report.addLine({ dataIndex:0, title: "", color: "green" }); report.addLine({ dataIndex:1, title: "", color: "red" }); report.render($("#reportPlaceholder1")); var report = CreateChart({ title: "   -  " }, type: "lineChart", sourceUrl: "/reports/data/1"); report.addLine({ dataIndex:0, title: "Hello Kitty", color: "#000" }); report.addLine({ dataIndex:1, title: "PokemonGo", color: "#222" }); report.addLine({ dataIndex:2, title: "Mustache", color: "#333" }); report.render($("#reportPlaceholder2")); 

Hier sehen wir, dass wir auf der Seite ein bis N lineChart-Diagramme haben, von denen jedes seine eigene Datenquelle, seinen eigenen Titel und seine eigene Liste von Indikatoren hat. Modelka:


 def get_model(): return { "charts": [ { "divId": "#reportPlaceholder1", "title": "   - ", "sourceUrl": "/reports/data/0", "series": [ {"dataIndex": 0, "title": "", "color": "green"}, {"dataIndex": 1, "title": "", "color": "red"}, ] }, { "divId": "#reportPlaceholder2", "title": "   -  ", "sourceUrl": "/reports/data/1", "series": [ {"dataIndex": 0, "title": "Hello Kitty", "color": "#000"}, {"dataIndex": 1, "title": "PokemonGo", "color": "#111"}, {"dataIndex": 2, "title": "Mustache", "color": "#222"}, ] } ] } 

Nun, die Vorlage:


 {{#charts}} var report = CreateChart({ title: "{{title}}" }, type: "lineChart", sourceUrl: "{{sourceUrl}}" ); {{#series}} report.addLine({ dataIndex:{{dataIndex}}, title: "{{title}}", color: "{{color}}" }); {{/series}} report.render($("{{divId}}")); {{/charts}} 

Bitte beachten Sie: Dieser "frontale" Ansatz zur Standardisierung erfordert einen separaten Aufwand, um die Werte im Modell zu überprüfen. Wenn ein Komma oder Anführungszeichen "Hello Kitty \" in der Reihe [0] .title auftaucht, fällt die Syntax der resultierenden Datei auseinander. Schreiben Sie daher Überprüfungsfunktionen und verwenden Sie sie beim Erstellen von Modellen. Verwenden Sie Formatierer, wenn die Template-Engine dies kann.




Der dritte Würfel flog durch die Tür und prallte mit einem Klopfen ab. Es ist auch nicht gut. Interessant. Aber können Sie den Würfel so rollen, dass er unter die Tür rutscht und das Ende des Korridors erreicht? Ist es möglich, Gummi in 3D zu drucken? Oder ist es besser, es mit so kleinen Ikosaedern gefüllt zu machen, die mit Luft gefüllt sind? ...


SQL-Abfragen


Der wählerische Leser wird sagen, dass dies auch die Codegenerierung ist, die Übersetzung von Konzepten von einer Programmiersprache in eine andere. Worauf wir dem wählerischen Leser antworten werden, dass die Arbeit mit SQL oder einer anderen Datenbankabfragesprache ein etwas separater Programmierbereich ist und es nicht jedem klar ist, dass SQL auch möglich ist, wenn js-Skripte durch Vorlagen generiert werden können. Daher werden wir Anfragen in einem separaten Fall stellen.


Und damit sich der wählerische Leser nicht langweilt, lassen wir im Artikel nur Beispiele einiger Fragen. Sie können selbst herausfinden, welches Modell und welche Vorlage hier besser geeignet sind. In den Beispielen auf dem Github können Sie sehen, was ich getan habe.


 SELECT * FROM hosts WHERE firmware_id=1 AND bmc_login='admin' ORDER BY ip DESC; SELECT * FROM hosts ORDER BY name LIMIT 3; SELECT host_type_id, COUNT(*) FROM hosts GROUP BY host_type_id; 

Vorlagen (einschließlich für SQL) und Codebeispiele finden Sie auf dem Github .

Source: https://habr.com/ru/post/de454418/


All Articles