كيف تكتب بسرعة موقع ويب أو تطبيق ويب ولا تنشغل بهواة الجمع

يصف هذا البرنامج التعليمي الصغير كيفية إنشاء تطبيق ويب تفاعلي باستخدام التقديم من جانب الخادم (SSR). جزء العميل هو تطبيق Vue مكتمل ، في حالتي باستخدام قالب MVVM. يعمل تطبيق الخادم على Flask microframework ، والذي يمكن أن يوفر نقاط النهاية ويعرض صفحات HTML جاهزة. يتم تقديم صفحات HTML (الموجودة في الدليل الفرعي myapp / templates) بواسطة محرك قوالب Jinja (مثبت على هيئة تبعية Flask).

ملاحظة: بسرعة لا يعني أن المقال مخصص للمبتدئين.

التقنيات والأطر المستخدمة:


بالنسبة لواجهة برمجة التطبيقات ، نستخدم بروتوكول JSON-RPC www.jsonrpc.org/specification . البروتوكول بسيط وسهل القراءة ، وبدون عكازات غير ضرورية ، يعمل على كل من الخادم والعميل.

التحضير


تثبيت الحزم المطلوبة

pip install flask flask-jsonrpc 

نحن إنشاء كتالوج المشروع وإعداد الهيكل في الداخل. يمكن العثور على بنية التطبيق الموصى بها هنا https://habr.com/ar/post/421887/

 mkdir -p myapp/{myapp/{static/{js,css},ns_api,templates},config,data} cd myapp 

قم بتنزيل ملفات إطار عمل JS و CSS الضرورية

 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 

هناك تبعية مسج هنا ، ولكن فقط لتشغيل Bootstrap

تطبيق قارورة الحد الأدنى


ملف Run.py للبدء اليدوي والاختبار

 #!/usr/bin/env python3 from myapp import app as application application.run(host='0.0.0.0', port=8000) 

ملف التكوين / default.py لتكوين التطبيق

 import os import sys #  DEBUG = True SQLDEBUG = False SESSION_COOKIE_NAME = 'myapp' SESSION_TYPE = 'filesystem' TITLE = '' DIR_BASE = '/'.join(os.path.dirname(os.path.abspath(__file__)).split('/')[:-1]) DIR_DATA = DIR_BASE + '/data' #    pwgen # : # pwgen -sy 64 SECRET_KEY = '''0123456789''' #  LOG_FILE = DIR_DATA + '/myapp.log' LONG_LOG_FORMAT = '%(asctime)s - [%(name)s.%(levelname)s] [%(threadName)s, %(module)s.%(funcName)s@%(lineno)d] %(message)s' LOG_FILE_SIZE = 128 #      


ملف التكوين / __ init__.py

 CONFIG = 'config.default' 


ملف 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) #  handler = RotatingFileHandler(app.config['LOG_FILE'], maxBytes=app.config['LOG_FILE_SIZE']*1024*1024, backupCount=1) handler.setLevel(logging.INFO) formatter = logging.Formatter(app.config['LONG_LOG_FORMAT']) handler.setFormatter(formatter) app.logger.addHandler(handler) # API from . import ns_api from . import views 

ملف myapp / ns_api / __ init__.py

 from flask_jsonrpc import JSONRPC from .. import app jsonrpc = JSONRPC(app, '/api') from . import logic 

ملف 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 


ملف 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) 


تعيين حقوق الإطلاق

 chmod +x run.py 


جانب العميل من واجهة المستخدم (الواجهة الأمامية ، الواجهة الأمامية)



ملف 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> 


ملف myapp / قوالب / 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> 

ملف 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 %} 

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


All Articles