[PYTHON] Persönliche Best-Practice-Vorlage, die verwendet werden soll, wenn Sie MVP mit Flask erstellen möchten

Beim Erstellen einer Webanwendung ist es praktisch, eine Vorlage zu haben. Dieses Mal möchte ich die Vorlage der Flask-App vorstellen, die ich normalerweise verwende.

Annahme

Site-Übersicht

image.png

Es ist eine Webanwendung, mit der ein einfaches PRJ erstellt und verwaltet wird.

Die wichtigsten Spezifikationen der Website lauten wie folgt.

Ordnerstruktur

Wie oben erwähnt, handelt es sich um eine einfache Anwendung. Es handelt sich also um eine Skala, die in eine Datei geschrieben werden kann. Ich möchte die Ordner ordentlich organisieren, um Skalierbarkeit und Lesbarkeit zu gewährleisten.

Insbesondere wurden die Ordner unter Berücksichtigung der folgenden Punkte organisiert.

Die tatsächliche Ordnerstruktur ist wie folgt.

tree


Stamm Stammordner
│  .gitignore         
│  LICENSE
│  main.py Der erste ausgeführte Anwendungsserver
│ Procfile Wird verwendet, wenn auf Heroku ausgeführt wird
│  README.md
│  requirements.txt Wird verwendet, wenn auf Heroku ausgeführt wird
│
├─.vscode VSCode-Konfigurationsdatei (für gitignore)
│      launch.Definieren Sie die JSON-Debug-Konfiguration
│      settings.json Python Spezifikation der virtuellen Umgebung usw.
│
Business─biz Geschäftslogikspeicher
│     prj.Schreiben Sie Geschäftslogik wie py DB-Operationen und API-Aufrufe
│
├─mw Middleware (Filter) Speicher
│     prj.Schreiben Sie die Gesamtverarbeitung der mittleren Ebene, die py route und biz verbindet
│
├─Routen-Routendefinitionsspeicher (Blueprint)
│     prj.Schreiben Sie eine Routing-Definition für jede Py-Ressource
│     top.Schreiben Sie eine Routing-Definition für jede Py-Ressource
│
├─statische Speicherung statischer Inhalte
│ ├Gemeinsamer statischer Inhalt, der auf allen Seiten verwendet wird
│  │  ├─css
│  │  │      page.css
│  │  │
│  │  └─js
│  │         page.js
│  │
│ ├prj Speicherung statischer Inhalte nach Ressourcen
│  │  ├─css
│  │  │      page.css
│  │  │
│  │  └─js
│  │          page.js
│  │
│ └top Speicherung statischer Inhalte nach Ressourcen
│      ├─css
│      │      page.css
│      │
│      └─js
│              page.js
│
└─ Vorlagen Jinja Template-Speicher
   │  footer.HTML-Fußzeile
   │  header.HTML Common Header
   │  layout.Definition des HTML-Seitenlayouts
   │  top.Individuelle Seite für jede HTML-Ressource (1 Dateisystem)
   │
└─prj Einzelne Seite nach Ressource (mehrseitiges System)
           entry.html
           search.html
           show.html

Überblick über die Verarbeitung

Starten Sie den Flask-Server

Führen Sie beim Starten des Flask-Servers main.py aus.

Online-Verarbeitung (Anzeige des TOP-Bildschirms)

Wenn der Flask-Server eine Anforderung des Benutzers an die TOP-Seite akzeptiert, wird er gemäß dem folgenden Ablauf verarbeitet. Es gibt keine bestimmte Logik in der Verarbeitung, wenn die TOP-Seite angezeigt wird und die entsprechende Vorlage einfach zurückgegeben wird, sodass der Verarbeitungsablauf wie folgt ist.

image.png

Online-Verarbeitung (Anzeige des PRJ-Bildschirms)

Der Verarbeitungsablauf des PRJ-Bildschirms wird anhand des PRJ-Detailbildschirms als Beispiel grob erläutert.

Im Gegensatz zum TOP-Bildschirm muss der PRJ-Bildschirm mehrere Aktionen wie Registrierung, Suche und Referenz implementieren. Daher hat jede Schicht die folgenden Rollen.

image.png

Auf diese Weise kann die Verarbeitung in jede Schicht unterteilt und auf leicht verständliche Weise verwaltet werden. Außerdem können Sie leichter erkennen, wo beim Hinzufügen neuer Funktionen Korrekturen vorgenommen werden müssen.

※たとえば、新しいアクションdeleteを追加したければ、route、mw、biz、templateの各prj.py/prj.htmlにdeleteアクションに対応するメソッドを追加する、など。

Die Verarbeitungsbeziehung zwischen Ebenen wird mit der folgenden Richtlinie implementiert.

Implementierungsdetails

maiy.py: Startvorgang des Flask-Servers

Importieren Sie * .py in den Routenordner und App.register_blueprint (), damit verschiedene Anfragen richtig weitergeleitet werden können.

main.py


from flask import Flask, redirect, url_for

app = Flask(__name__)

from route.top import top
from route.prj import prj

app.register_blueprint(top)
app.register_blueprint(prj)

if __name__ == '__main__':
  app.debug = True
  app.run(host='127.0.0.1',port=5000)

route/top.py Nur der Vorgang zum Anzeigen des TOP-Bildschirms. Weil es das Routing ist, wenn auf die Site-Route (https: // my-site.com /) zugegriffen wird Das url_prefix von Blueprint setzt '' (leeres Zeichen).

route/top.py


from flask import Flask, render_template, request, Blueprint

top = Blueprint('top', __name__, url_prefix='')

@top.route('/')
def index():
  return render_template('top.html', title='TOP')

route/prj.py prj System Routing Definition. Setzen Sie "/ prj" in url_prefix von Blueprint. Auf diese Weise können Sie Anfragen für "https: // my-site.com / prj / ~" annehmen. Durch Definieren einer Route wie "@ prj.route (" / search ", Methods = [" POST ")) werden verschiedene Aktionen wie" https: // my-site.com / prj / search "akzeptiert. Wird in der Lage sein.

route/prj.py


from flask import Flask, render_template, request, Blueprint

from mw.prj import parse, search_prj, get_prj, create_prj, update_prj

prj = Blueprint('prj', __name__, url_prefix='/prj')

@prj.route('/')
def index():
  return render_template('prj/search.html', title='Projektsuche', prj={})

@prj.route('/search', methods=['POST'])
def search():
  q = parse(request)
  if q is None:
    #Vorzeitige Rückkehr
    return jsonify({'code': 'W00100','message': 'Der eingegebene Wert ist ungültig.'})
  
  #Suchen Sie die Datenbank mit den eingegebenen Bedingungen
  data = search_prj(q)

  #Suchergebnisse anzeigen
  return jsonify({'data': data})

@prj.route('/show/<prj_id>', methods=['GET'])
def show(prj_id):
  if prj_id is None:
    #Vorzeitige Rückkehr
    return render_template('prj/show.html', title='Projekt Details', data={})
  
  # prj_Suche DB nach ID
  data = get_prj(prj_id)

  #Detailseite anzeigen
  return render_template('prj/show.html', title='Projekt Details', data=data)

@prj.route('/entry', methods=['GET'])
def entry():
  #Erstanzeige des PRJ-Eingabebildschirms
  return render_template('prj/entry.html', title='Projekterstellung')

@prj.route('/create', methods=['POST'])
def create():
  #Erstellen Sie PRJ
  data = create_prj(parse(request))
  #Detailseite anzeigen
  return render_template('prj/show.html', title='Projekt Details', data=data, message='Ich habe ein Projekt erstellt.')

mw/prj.py Schreiben Sie einen Überprüfungsprozess und einen Biz-Aufrufprozess, um jede Aktion zu verarbeiten.

mw/prj.py


from flask import request
import biz.prj as prj

def parse(request):
  #Ausgelassen

def search_prj(dto):
  #Ausgelassen

def get_prj(prj_id):
  """
Holen Sie sich das Projekt mit der angegebenen Projekt-ID
  """
  return prj.get(prj_id)

def create_prj(dto):
  #Ausgelassen

def update_prj(data, dto):
  #Ausgelassen

biz/prj.py Schreib-API-Zugriffsverarbeitung und DB-Zugriffsverarbeitung. Das folgende Beispiel beschreibt einen Abrufprozess, der eine API über HTTP aufruft. Da API-Endpunkte und API-Schlüssel als System vertrauliche Informationen sind, werden sie so eingestellt, dass sie aus Umgebungsvariablen gelesen werden.

biz/prj.py


import requests
import os

api_endpoint = os.environ.get('API_ENDPOINT')
headers = {
  'x-api-key':os.environ.get('API_KEY')
}

def get(prj_id):
  r_get = requests.get(api_endpoint + '/prj/' + prj_id, headers=headers)
  return r_get.json()

template/layout.html Vorlage für alle HTML-Seiten. CSS und JS, die allen Seiten gemeinsam sind, können in dieser layout.html gelesen und definiert werden. Ich versuche es nicht auf jede Seite zu schreiben.

"{% Block css%}" und "{% block js%}" sind so definiert, dass CSS und JS für jede Seite einzeln gelesen werden können.

Der Inhalt des Body-Tags wird als gemeinsamer Header, Inhalt jeder Seite und gemeinsamer Fußzeile definiert.

<link rel="stylesheet" href="/static/common/css/page.css" /> <script src="/static/common/js/page.js"></script> Beim Lesen von statischem Inhalt unter statisch werden href und src mit einem Schrägstrich wie "/ static" definiert. Dies ist dieselbe layout.html für allgemeinen statischen Inhalt unter "static / common /", auch wenn sich die Seitenhierarchie von "template / top.html" und "template / prj / show.html" unterscheidet. Dies ist so, dass es mit gelesen werden kann.

template/layout.html


<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<meta http-equiv="Content-Type" content="text/html" charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0" />
<!--Gemeinsamer Stil-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.8.2/css/bulma.min.css">
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<link rel="stylesheet" href="/static/common/css/page.css" />
<!--Einzelne Seite CSS-->
{% block css %}
{% endblock %}
</head>
<body class="has-navbar-fixed-top">

  <!--Header-->
  {% include "header.html" %}

  <!--Inhalt-->
  {% block content %}
  {% endblock %}

  <!--Fusszeile-->
  {% include "footer.html" %}

  <!--Gemeinsame JS-->
  <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
  <script src="/static/common/js/page.js"></script>

  <!--Einzelne Seite JS-->
  {% block js %}
  {% endblock %}
</body>
</html>

template/top.html

template/top.html


{% extends "layout.html" %}
{% block css %}
<link rel="stylesheet" href="/static/top/css/page.css" type="text/css" />
{% endblock %}

{% block content %}
<section class="hero is-medium is-primary is-bold">
  <div class="hero-body">
    <div class="container">
      <div class="columns is-centered">
        <div class="column is-narrow">
          <h1 class="title is-1">
            Site Concept
          </h1>
        </div>
      </div>
    </div>
  </div>
</section>
{% endblock %}

{% block js %}
<script async src="/static/top/js/page.js"></script>
{% endblock %}

template/prj/show.html

template/prj/show.html


{% extends "layout.html" %}
{% block css %}
<link rel="stylesheet" href="/static/prj/css/page.css" type="text/css" />
{% endblock %}

{% block content %}
<section class="hero is-medium is-primary is-bold">
  <div class="hero-body">
    <div class="container">
      <div class="columns is-centered">
        <div class="column is-narrow">
          <h1 class="title is-1">
            {{ data['name'] }}
          </h1>
        </div>
      </div>
    </div>
  </div>
</section>
{% endblock %}

{% block js %}
<script async src="/static/prj/js/page.js"></script>
{% endblock %}

Vollständiger Code für die Beispiel-App

Der mit dieser Vorlage erstellte Anwendungscode wird auf Github veröffentlicht. https://github.com/KeitaShiratori/ripple

Recommended Posts

Persönliche Best-Practice-Vorlage, die verwendet werden soll, wenn Sie MVP mit Flask erstellen möchten
Verwenden Sie aggdraw, wenn Sie mit Kissen schön zeichnen möchten
Wenn Sie ein Objekt mit Anforderungen mithilfe der Flasche senden möchten
Wenn Sie es so verwenden möchten, wie es ist, wenn Sie es mit Lambda-Memo verwenden
Ein Gist-Repository, das Sie verwenden können, wenn Sie es mit ansible ausprobieren möchten
Bedeutet Memo, wenn versucht wird, maschinelles Lernen mit 50 Bildern durchzuführen
Wenn Sie einen Discord-Bot mit Python erstellen möchten, verwenden wir ein Framework
Wenn Sie mit dem Django REST-Framework filtern möchten
[AWS] Was tun, wenn Sie mit Lambda pfeifen möchten?
Wenn Sie die Anfangsdaten von Django mit Relationen registrieren möchten
Wenn Sie python2.x unter modernem Gentoo Linux verwenden möchten
Ich kenne? Datenanalyse mit Python oder Dingen, die Sie mit numpy verwenden möchten, wenn Sie möchten
[Python] Wenn Sie alle Variablen in einer anderen Datei verwenden möchten
Wenn Sie das Intervall der Achsenskala mit APLpy anpassen möchten
Wenn Sie eine Spalte spaltenweise durch einen fehlenden Wert (NaN) ersetzen möchten
Persönliche Best Practices bei der Feinabstimmung mit Chainer
So erstellen Sie eine Umgebung, wenn Sie Python2.7 nach der Installation von Anaconda3 verwenden möchten
[OpenCV] Wenn Sie überprüfen möchten, ob es mit imread richtig gelesen wird
Ich möchte MATLAB feval mit Python verwenden
Ich möchte ein Spiel mit Python machen
Wenn Sie den Chrome-Treiber aktualisieren möchten.
Ich möchte Temporäres Verzeichnis mit Python2 verwenden
Ich möchte -inf nicht mit np.log verwenden
Ich möchte ip vrf mit SONiC verwenden
[Python] Ich möchte mit Flask ein statisches Verzeichnis hinzufügen. [Ich möchte etwas anderes als statisch verwenden.]
[Python] Ich möchte nur den Index verwenden, wenn ich eine Liste mit einer for-Anweisung schleife
Wenn die Variable, die Sie in Matplotlib als hochgestellt verwenden möchten, aus zwei oder mehr Zeichen besteht
Was tun, wenn Sie bei Verwendung von ortoolpy.logistics_network keine japanischen Spaltennamen verwenden möchten?
Wenn Sie Cython verwenden möchten, schließen Sie auch python-dev ein
Versuchen Sie, mit MVC eine RESTful-API mit Flask 1.0.2 zu erstellen
Links, um mit Sublime Text zu tun, was Sie wollen
Dinge zu tun, wenn Sie anfangen, sich mit Django zu entwickeln
Wenn Sie in der for-Anweisung plt.save möchten
Site-Hinweise zur Verwendung von NetworkX mit Python
Die Programmiersprache, die Sie verwenden möchten
Notieren Sie sich, was Sie in Zukunft mit Razpai machen möchten
Nützliche Operation, wenn Sie alle Probleme in mehreren Programmiersprachen mit Codewars lösen möchten
[Python] Wenn Sie Ihr eigenes Paket im oberen Verzeichnis importieren und verwenden möchten
Was tun, wenn beim Versuch, pip mit pyenv zu verwenden, ein undefinierter Fehler angezeigt wird?
Einfach zu bedienende Flasche
So erstellen Sie mit Flask einen BOT für Cisco Webex-Teams
[Django] Memorandum, wenn Sie asynchron kommunizieren möchten [Python3]
Ich möchte R-Funktionen einfach mit ipython notebook verwenden
Kenntnisse, die Sie beim Programmieren von Wettbewerben mit Python2 benötigen
Ich möchte einen Blog-Editor mit dem Administrator von Django erstellen
[Python] Hinweise beim Versuch, Numpy mit Cython zu verwenden
Ich möchte ein Klickmakro mit pyautogui (Wunsch) erstellen.
Wenn Sie wissen, wie Jinja2 verwendet wird, wird die Entwicklung mit Flask intelligenter
Ich möchte ein Klickmakro mit pyautogui (Outlook) erstellen.
[Python] Ich möchte die Option -h mit argparse verwenden
Ich möchte eine virtuelle Umgebung mit Jupyter Notebook verwenden!
Wenn Sie möchten, dass Ihre Kollegen dieselbe Sprache verwenden
Wenn Sie einen UNIX-Befehl in Python ausführen möchten
Wenn Sie mehrere Versionen derselben Python-Bibliothek verwenden möchten (virtuelle Umgebung mit venv)