Trois exemples non évidents d'utilisation de moteurs de modèle dans le backend

D'une part, le sujet était bien carré. Par contre, c'était rond. Mais du troisième côté, avec lequel le triangle devrait être, l'objet est sorti incurvé et oblique.


- Est-ce qu'Alyoshenka va dans la salle de réunion? - Lenochkina coincé dans la porte du visage intéressé.
- Alyoshenka n'assiste pas à la réunion. Aleshenka écrit un article.
- A propos des cubes?
- Quels autres cubes? - J'ai baissé les yeux, entre mes mains et la vérité était un cube malheureux. C'est une balle. C'est un losange.
- Pas pour les cubes! Et pas à propos des balles. À propos des modèles.
"Je vais leur dire ça!" Motif, ah. - Helen courait déjà dans le couloir.


"À propos des modèles. Même environ trois modèles différents." Plus précisément, environ trois raisons d'utiliser des modèles dans le code serveur. Et aucune de ces raisons ne concernera le HTML.


Dans les exemples, j'ai utilisé la syntaxe Moustache , en raison de la syntaxe laconique et de la présence d'implémentations pour tout ce qui bouge. Moustache ne se permet pratiquement aucune liberté, contrairement, par exemple, à .Net Razor, qui vous permet de coder à l'intérieur du modèle, donnant ainsi un mauvais exemple aux développeurs faibles.


Les exemples de code seront en python. L'implémentation de Moustache pour Python est appelée pystache .


Donc, trois raisons de laisser ta vie votre code.


Artefacts de texte


Si vous avez un système à l'intérieur duquel certaines données existent - par exemple, des données dans une base de données relationnelle ou des données obtenues via des appels d'API, vous devez parfois créer des artefacts basés sur ces données.


L'artefact peut être, par exemple, un fichier JSON ou texte brut, une pièce jointe, une réponse HTTP. L'essentiel - un artefact est essentiellement le résultat de l'application d'une fonction à partir d'une partie relativement compacte des données de votre système. Et l'artefact a sa propre syntaxe.


L'artefact peut être un relevé bancaire au format texte à télécharger sur le système hérité. L'artefact peut être le déchargement d'un chèque électronique sous la forme d'un fichier .json, qui sera envoyé en pièce jointe au client par courrier.


Dans tous ces cas, vous simplifierez considérablement votre vie en utilisant des modèles d'artefact.


Qu'est-ce qu'un moteur de modèle? Il s'agit d'une bibliothèque qui prendra un modèle objet (contexte), prendra un modèle, s'appliquera les uns aux autres - et donnera le résultat. Le modèle d'objet et le modèle sont préparés par le programmeur. Le résultat final est préparé par le moteur de modèle.


Exemple: essayez de créer un SMS sur la commande.


Tout d'abord, préparez le modèle d'objet:


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 

Le code est purement factice. Dans le code réel, il peut y avoir une requête de base de données, une sorte de logique pour calculer les valeurs (par exemple, nous calculons la valeur de total.amount en fonction des articles de la commande).


Faites attention à quelques choses:


  • Ce n'est PAS un modèle objet de la commande, c'est quelque chose de plus simple, préparé pour être utilisé dans le modèle. Les valeurs "sumRub" et "total.amount" dans le modèle commercial réel ne doivent pas être textuelles, la valeur "virgule" du tableau de lignes dans le modèle objet n'appartient pas, elle est uniquement nécessaire pour simplifier le rendu (pystache ne peut pas comprendre lui-même que l'élément de liste est le dernier et après cela, il n'est pas nécessaire de mettre une virgule.
  • Le type de champ "montant" est le texte et ce texte est formaté pour la sortie dans le modèle. Si votre moteur de modèle prend en charge les formateurs (quelque chose comme "... {someValue | asMoney}"), alors le formatage directement dans le modèle n'est pas nécessaire.
  • Le texte du modèle devrait être légèrement différent pour les clients d'Uryupinsk (le gestionnaire s'est précipité au dernier moment et a demandé d'ajouter - l'entreprise a vraiment demandé, ils ont soudainement lancé une campagne de marketing pour la ville). Par conséquent, nous avons ajouté la valeur booléenne "posInUrupinsk" au modèle et l'avons utilisée dans le modèle.
  • Il est préférable de ne pas réutiliser le modèle à partir du modèle, sauf pour le rendu d'autres modèles

Le texte du modèle de moustache ressemble à ceci:


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

Nous voyons dans le modèle que l'en-tête du document pour les commandes à Uryupinsk est différent des autres villes. Nous voyons également qu'à la fin de la dernière ligne avec la position des matières premières, il y a un point, et dans toutes les premières positions il y a un point-virgule. L'attribut "virgule" et la méthode "add_comma" dans le générateur de modèle en sont responsables.


Le code qui applique le contexte au modèle est 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) 

Résultat:


    !        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 

Autre astuce: si la tâche le permet, enregistrez le modèle lui-même avec le modèle rendu (par exemple, au format JSON). Cela aidera au débogage et au dépannage.




L'imprimante a grincé trois fois, émettant un nouveau modèle. Le côté triangulaire était maintenant un triangle parfait. Les deux autres côtés étaient carrés. Le réseau neuronal a vécu sa propre vie et a refusé de donner un modèle modèle primitif à tous égards.


"Je vais donner un cube à Helen." Pensai-je. Laissez-le se réjouir.


Génération de code


Vous devrez peut-être créer du JavaScript lors de l'exécution depuis l'intérieur du backend. Pourquoi? Pour créer des rapports côté navigateur, par exemple. Ou obtenez un script en F # à partir d'un programme Go. Ou le code Kotlin de ReactJS (je ne peux pas imaginer pourquoi cela pourrait être nécessaire, mais tout à coup, vous avez des inclinations spécifiques).


Dans le cas de la génération de code, il est préférable d'écrire d'abord avec vos mains le code résultant (ce que nous voulons générer) puis de le décomposer en un modèle et un modèle. Cette approche nous sauvera de nostalgie complexité excessive du modèle. Il n'est jamais trop tard pour compliquer un modèle, mais il vaut mieux commencer par un simple.


 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")); 

Ici, nous voyons que nous avons de un à N graphiques LineChart sur la page, chacun ayant sa propre source de données, son titre et sa liste d'indicateurs. 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"}, ] } ] } 

Eh bien, le modèle:


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

Remarque: cette approche «frontale» de la normalisation nécessite un effort distinct pour filtrer les valeurs dans le modèle. si dans la série [0] .title, nous obtenons une virgule ou un guillemet - "Hello Kitty \" "- la syntaxe du fichier résultant s'effondrera. Par conséquent, écrivez les fonctions de filtrage et utilisez-les lors de la création de modèles. Utilisez des formateurs si le moteur de modèle sait comment.




Le troisième dé passa par la porte et rebondit en frappant. Ce n'est pas bon non plus. Intéressant. mais pouvez-vous rouler le cube pour qu'il se glisse sous la porte et atteigne la fin du couloir? Est-il possible d'imprimer du caoutchouc en 3D? Ou vaut-il mieux le remplir de si petits icosaèdres remplis d'air? ...


Requêtes SQL


Le lecteur pointilleux dira qu'il s'agit également de génération de code, de traduction de concepts d'un langage de programmation à un autre. À laquelle nous répondrons au lecteur pointilleux que travailler avec SQL ou avec tout autre langage de requête de base de données est un domaine de programmation légèrement séparé et il n'est pas évident pour tout le monde que si les scripts js peuvent être générés par des modèles, alors SQL est également possible. Par conséquent, nous émettrons des demandes dans un cas distinct.


Et pour que le lecteur pointilleux ne s'ennuie pas, nous ne laissons dans l'article que des exemples de quelques requêtes. Vous pouvez vous-même déterminer quel modèle et quel modèle conviennent le mieux ici. Dans les exemples sur le github, vous pouvez voir ce que j'ai fait.


 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; 

Des modèles (y compris pour SQL) et des exemples de code peuvent être trouvés sur le github .

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


All Articles