Este pequeño tutorial describe cómo crear una aplicación web reactiva mediante el Representación del lado del servidor (SSR). La parte del cliente es una aplicación Vue completa, en mi caso usando la plantilla MVVM. La aplicación del servidor se ejecuta en el microframework Flask, que puede proporcionar puntos finales y representar páginas HTML listas para usar. Las páginas HTML (ubicadas en el subdirectorio myapp / templates) son representadas por el motor de plantillas Jinja (instalado como una dependencia de Flask).
Nota: rápidamente no significa que el artículo esté destinado a principiantes.
Tecnologías y marcos utilizados:
Para la API, utilizamos el protocolo JSON-RPC
www.jsonrpc.org/specification . El protocolo es simple, fácil de leer y, sin muletas innecesarias, funciona tanto en el lado del servidor como del cliente.
Preparación
Instale los paquetes requeridos
pip install flask flask-jsonrpc
Creamos el catálogo de proyectos y preparamos la estructura interior. La estructura de aplicación recomendada se puede encontrar aquí
https://habr.com/en/post/421887/ mkdir -p myapp/{myapp/{static/{js,css},ns_api,templates},config,data} cd myapp
Descargue los archivos de marco JS y CSS necesarios
wget -O myapp/static/css/bootstrap.min.css https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css wget -O myapp/static/js/vue.min.js https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js wget -O myapp/static/js/axios.min.js https://unpkg.com/axios/dist/axios.min.js
Aquí hay una dependencia jquery, pero solo para que Bootstrap funcione
Aplicación mínima de matraz
Archivo Run.py para inicio manual y prueba
Archivo Config / default.py para configurar la aplicación
import os import sys
Config / __ init__.py archivo
CONFIG = 'config.default'
Archivo myapp / __ init__.py
import config import logging from flask import Flask from logging.handlers import RotatingFileHandler app = Flask(__name__) app.config.from_object(config.CONFIG) app.config.from_envvar('FLASKR_SETTINGS', silent=True)
Archivo myapp / ns_api / __ init__.py
from flask_jsonrpc import JSONRPC from .. import app jsonrpc = JSONRPC(app, '/api') from . import logic
Archivo myapp / views.py
from myapp import app from flask import render_template @app.route('/') def index(): pagedata = {} pagedata['title'] = app.config['TITLE'] pagedata['data'] = { "A": True, "B": False, "result": False } body = render_template('index.html', pagedata=pagedata) return body
Archivo myapp / ns_api / logic.py
import operator from . import jsonrpc @jsonrpc.method('logic.and(A=bool, B=bool)') def logic_and(A, B): """ """ return operator.and_(A, B) @jsonrpc.method('logic.not(A=bool)') def logic_not(A): """ """ return operator.not_(A) @jsonrpc.method('logic.or(A=bool, B=bool)') def logic_or(A, B): """ """ return operator.or_(A, B) @jsonrpc.method('logic.xor(A=bool, B=bool)') def logic_xor(A, B): """ """ return operator.xor(A, B)
Establecer derechos de lanzamiento
chmod +x run.py
Lado del cliente de la interfaz de usuario (front-end, front-end)
Archivo myapp / templates / header.html
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css" /> <script src="/static/js/vue.min.js"></script> <script src="/static/js/axios.min.js"></script> <title>{{ pagedata['title'] }}</title> </head>
Archivo myapp / templates / skeleton.html
<!DOCTYPE html> <html lang="ru"> {% include 'header.html' %} <body> <section id="app"> <div class="container-fluid"> {% block content %} {% endblock %} </div> </section> {% block script %} <script type="text/javascript"> var app = new Vue({ el: '#app', data: { }, methods: { } }) </script> {% endblock %} </body> </html>
Archivo myapp / templates / index.html
{% extends "skeleton.html" %} {% block content %} <h1> </h1> <a href="http://127.0.0.1:8000/api/browse">http://127.0.0.1:8000/api/browse</a> <h2>API</h2> <pre>curl -i -X POST \ -H "Content-Type: application/json; indent=4" \ -d '{ "jsonrpc": "2.0", "method": "logic.and", "params": { "A": true, "B": true }, "id": "1" }' http://127.0.0.1:8000/api </pre> <h3></h3> <ul> <li>logic.and(A, B)</li> <li>logic.not(A)</li> <li>logic.or(A, B)</li> <li>logic.xor(A, B)</li> </ul> <h3>API</h3> <div class="btn-group"> <div class="btn btn-outline-success" v-if="A" v-on:click="changeA"></div> <div class="btn btn-outline-danger" v-else v-on:click="changeA"></div> <div class="btn btn-outline-secondary disabled"></div> <div class="btn btn-outline-success" v-if="B" v-on:click="changeB"></div> <div class="btn btn-outline-danger" v-else v-on:click="changeB"></div> <div class="btn btn-outline-secondary disabled">=</div> <div class="btn btn-success disabled" v-if="result"></div> <div class="btn btn-danger disabled" v-else></div> </div> {% endblock %} {% block script %} <script type="text/javascript"> var app = new Vue({ el: '#app', data: {{ pagedata['data']|tojson|safe }}, methods: { changeA: function() { var vm = this; vm.A = !vm.A; vm.update(); }, changeB: function() { var vm = this; vm.B = !vm.B; vm.update(); }, update: function() { var vm = this; axios.post( '/api', { "jsonrpc": "2.0", "method": 'logic.and', "params": { "A": vm.A, "B": vm.B }, "id": 1 } ).then( function(response) { if ('result' in response.data) { vm.result = response.data['result']; } } ); } } }) </script> {% endblock %}