Flask, WSGI, Werkzeug, Jinja2, Django

5 (100%) 8 vote[s]

Вначале рассмотрим, что такое Flask, основные связанные с ним понятия, кратко просмотрим базовый синтаксис, типы данных, основные функции, последовательности, лупы, модули, классы Python. В конце предлагаем разобрать пример создания простого приложения Flask.

WSGI и Werkzeug

WSGI (Web Server Gateway Interface) — это интерфейс шлюза веб-сервера. Это спецификация, которая описывает, как веб-сервер взаимодействует с веб-приложениями и как веб-приложения могут быть объединены в цепочку для обработки одного запроса.

WSGI — это стандарт Python, подробно описанный в PEP 3333.

WSGI-серверы появились в начале 2000-х годов специально для того, чтобы веб-серверы могли взаимодействовать с приложениями, написанными на языке Python. Модуль Apache, известный как mod_python, разработанный в конце 90-х годов, на тот момент обрабатывал большую часть Python-приложений. Однако mod_python не был официальной спецификацией. Он был просто создан в помощь веб-разработчикам, чтобы они могли запускать код Python на сервере. К сожалению, такой подход был небезопасным, и разработчики начали искать новое решение.

WSGI (Web-Server Gateway Interface) является потомком CGI (Common Gateway Interface «общий интерфейс шлюза»). Когда веб начал развиваться, CGI разрастался из-за необходимости поддержки всё большего количества языков и из-за отсутствия других решений. Однако, такое решение было медленным и ограниченным. WSGI был разработан как интерфейс для маршрутизации запросов от веб-серверов (Apache, Nginx и т.д.) на веб-приложения.

WSGI — стандарт обмена данными между веб-сервером (backend) и веб-приложением (frontend). Под это определение попадают многие вещи, в том числе и CGI.

WSGI — это в первую очередь возможность комбинировать различные back- и frontend’ы.

Стандарт описывает интерфейсы веб-приложения и веб-сервера:

    • Сервер— тут чуть сложнее. В переменных окружения, к стандартным переменным веб-сервера, добавляются WSGI-специфичные. В PEP 333 приведен пример.
    • Прослойка, middleware. Middleware «работает» в обе стороны, имеет идентичный входной и выходной интерфейс (по аналогии с с декоратором). Middleware добавляет некую функциональность в исходное веб-приложение, например live debug, или http auth. Причем, можно выстраивать цепочки middleware.
    • Приложение— принимает в качестве параметров переменные окружения (в виде словаря) и исполняемый объект выполнения запроса. Возвращает итератор.

По стандарту, WSGI-приложение должно удовлетворять следующим требованиям:

    • должно быть вызываемым (callable) объектом (обычно это функция или метод);
    • принимать два параметра:
      • словарь переменных окружения (environ);
      • обработчик запроса (start_response) вызывать обработчик запроса с кодом HTTP-ответа и HTTP-заголовками;
    • возвращать итерируемый объект с телом ответа.

Вот фреймворки, поддерживающих WSGI:

WSGI-серверы выпускаются в различных вариациях. Одни нацелены на fullstack-решение, в то время как другие хорошо подходят для конкретных фреймворков. Например, Gunicorn работает с Django прямо из коробки.

Вот шесть наиболее популярных WSGI-серверов на сегодня:

      • асинхронный Bjoern;
      • сервер для создания услуг хостинга с fullstack-решением uWSGI;
      • модуль HTTP-сервера Apache mod_wsgi;
      • для выполнения асинхронных операций ввода-вывода, поддерживающий веб-сокеты и использующий picoevи greenlet  WSGI-сервер Meinheld;
      • высокоскоростной, минималистичный thread-pooled HTTP-сервер CherryPy;
      • WSGI-сервер для использования в UNIX-системах Gunicorn.

Werkzeug немецкое существительное: «инструмент». Этимология: werk («работа»), zeug («материал»).

Werkzeug — это не фреймворк, а служебная библиотека с утилитами для создания вашего собственного фреймворка или приложения WSGI. Он начинался как простая коллекция различных утилит для приложений WSGI и стал одной из самых передовых библиотек утилит WSGI. WSGI сам по себе является протоколом или соглашением, которое гарантирует, что ваше веб-приложение может взаимодействовать с веб-сервером, и, что более важно, хорошо работают вместе.

Простейшим примером WSGI-приложения может служить такая функция-генератор:

  1. def simplest_wsgi_app(environ, start_response):
  2.      start_response('200 OK', [('Content-Type', 'text/plain')])
  3.      yield 'Hello, world!'

Приложение WSGI — это то, что вы можете вызвать и передать окружение и вызов start_response. Среда содержит всю поступающую информацию, start_response функция может быть использована для указания начала ответа.

С Werkzeug вам не нужно иметь дело напрямую с объектами запросов и ответов для работы с ними. Данные запроса принимают объект среды и позволяют вам получить доступ к данным из этой среды удобным способом. Объект ответа сам по себе является приложением WSGI и обеспечивает более удобный способ создания ответов.

Вот как вы могли бы написать это приложение с объектами ответа:

  1. from werkzeug.wrappers import Response
  2.  
  3. def application(environ, start_response):
  4.     response = Response('Hello World!', mimetype='text/plain')
  5.     return response(environ, start_response)

А вот расширенная версия, которая просматривает строку запроса в URL-адресе (что более важно — параметр имени в URL-адресе, чтобы заменить «мир» на другое слово):

  1. from werkzeug.wrappers import Request, Response
  2.  
  3. def application(environ, start_response):
  4.     request = Request(environ)
  5.     text = 'Hello %s!' % request.args.get('name', 'World')
  6.     response = Response(text, mimetype='text/plain')
  7.     return response(environ, start_response)

Flask

Flask — (сайт разработчика) это облегченная среда веб-приложений WSGI, является микрофреймворком для создания вебсайтов на языке Python. Он предназначен для быстрого и легкого начала работы с возможностью масштабирования до сложных приложений. Он начинался как простая оболочка вокруг Werkzeug и Jinja и стал одной из самых популярных платформ веб-приложений Python.

Flask (см. на https://flask.palletsprojects.com/en/1.1.x/) предлагает возможности, но не применяет никаких зависимостей или макетов проекта. Разработчик должен выбрать инструменты и библиотеки, которые он хочет использовать. Сообщество предоставляет множество расширений, облегчающих добавление новых функций.

Flask (см. официальный сайт) оборачивает Werkzeug, используя его для обработки деталей WSGI, предоставляя больше структуры и шаблонов для создания мощных приложений.

Jinja2, Django

Jinja2 — полнофункциональный шаблонизатор для Python. Jinja — это современный и удобный для разработчиков язык шаблонов для Python, созданный по образцу шаблонов Django. Он быстрый, широко используемый и безопасный с дополнительной средой выполнения изолированных шаблонов:

  1. <title>{% block title %}{% endblock %}</title>
  2. <ul>
  3. {% for user in users %}
  4.   <li><a href="{{ user.url }}">{{ user.username }}</a></li>
  5. {% endfor %}
  6. </ul>

Он имеет полную поддержку Unicode, опционально интегрированную среду выполнения в песочнице, широко используется и лицензирован BSD.

Jinja2 — один из наиболее часто используемых шаблонов для Python. Он вдохновлен системой шаблонов Django, но расширяет ее выразительным языком, который дает авторам шаблонов более мощный набор инструментов. Кроме того, он добавляет изолированное выполнение и дополнительное автоматическое экранирование для приложений, где важна безопасность. Jinja2 — это библиотека для Python, разработанная для обеспечения гибкости, скорости и безопасности.

Работает на широком диапазоне версий Python от 2.5 до текущих версий, включая Python 3.

Если вы знакомы с другими текстовыми языками шаблонов, такими как Smarty или Django, вы должны легко освоиться в Jinja2. Он удобен как для дизайнеров, так и для разработчиков, придерживаясь принципов Python и добавляя функциональность, полезную для шаблонных сред.

Важно! Jinja 2.7 имеет экспериментальную поддержку Python> = 3.3. Это означает, что все юнит-тесты работают с последними версиями Python, но могут быть небольшие ошибки и поведение может быть непоследовательным.

Django — это высокоуровневая веб-инфраструктура Python, которая позволяет быстро создавать безопасные и поддерживаемые веб-сайты. Построенный опытными разработчиками, Django заботится о многих проблемах веб-разработки, поэтому вы можете сосредоточиться на написании своего приложения без необходимости изобретать колесо. Это бесплатный и открытый источник, имеет процветающее и активное сообщество, отличную документацию и множество опций для бесплатной и платной поддержки. Будет рассмотрен в следующих статьях.

Заметки второй недели: Python и Flask

Python

Рассмотрим основной синтаксис, с которым будем встречаться при работе с первым приложением на Flask:

    • Для тех, кто незнаком, Python — это интерпретируемый язык, который будет использоваться для создания динамических веб-сайтов и веб-приложений.
    • Некоторый базовый синтаксис Python:
      • Вывести строку на экран:
        1. print("Hello, world!")
      • Вывести строку формата (имена переменных, заключенные в {}, будут заменены значениями переменных)
        1. print(f"Hello, {name}!")
      • Установить переменную name для пользовательского ввода, возвращаемого input()
        1. name = input()
      • Условный оператор:
        1. if x > 0:
        2.       print("x is positive")
        3.   elif x < 0:
        4.       print("x is negative")
        5.   else:
        6.       print("x is zero")
        • elif и else блоки не являются обязательными.
        • Обратите внимание, что отступы в Python не стилистические, а используются для разграничения блоков кода. В этом примере интерпретатор Python знает, где заканчивается условный блок  if и начинается блок  elif из-за изменений отступа.

Типы данных

    • int: целочисленное значение;
    • float: значение с плавающей точкой;
    • str: текстовая строка;
    • bool: логическое значение (True или False);
    • None: пустое значение;
    • Обратите внимание, что Python является слабо типизированным языком.

Последовательности

  • Строки:
  1. name = "Alice"
  2. print(name[0])
    • Строки представляют собой последовательность символов и могут быть проиндексированы как таковые.
  • Кортежи (Tuples):
  1. coordinates = (10.0, 20.0)
  2. print(coordinates[1])
    • Кортежи — это неизменные наборы значений под одним именем, которые можно индексировать позиционно.
  • Списки:
  1. names = ["Alice", "Bob", "Charlie"]
  2. print(names[2])
    • Списки представляют собой изменяемые коллекции значений под одним именем, которые можно индексировать позиционно.
    • Индексирование вне диапазона вызывает «исключение». В этом случае получим IndexError потому что в names Python нет четвертого значения для возврата:
  1. names = ["Alice", "Bob", "Charlie"]
  2. print(names[4])
  • Обратите внимание, что любая последовательность в Python может содержать любое количество типов данных.
  • Наборы:
  1. s = set()
  2. s.add(1)
  3. s.add(3)
  4. s.add(5)
    • Наборы представляют собой неупорядоченную коллекцию уникальных предметов. Поскольку они неупорядочены, они не могут быть проиндексированы.
    • s — это набор, неупорядоченный набор уникальных предметов.
  • Словари:
  1. ages = {"Alice": 22, "Bob": 27}
  2. print(ages["Alice"])
  3. ages["Alice"] += 1
    • Словари  похожи на списки, за исключением того, что они неупорядочены и их value индексы индексируются в keys.
    • += Увеличивает левую часть (22) на правую (1).

Loops

  1. for i in range(5):
  2.   print(i)
  • Циклы for перебирают свои тела ограниченное количество раз. В этом случае количество итераций устанавливается с помощью range(5).
  • range(5) возвращает последовательность чисел, начиная с 0 до 4. Каждое значение передается i один раз, в результате чего цикл выполняется в общей сложности 5 раз. I обычно называется переменной итератора.
  1. names = ["Alice", "Bob", "Charlie"]
  2. for name in names:
  3.    print(name)
  • Этот цикл for повторяется в names и является списком. Каждое значение в списке присваивается по порядку итератору name один раз.

Функции

  1. def square(x):
  2.     return x * x
  3.  
  4. for i in range(10):
  5.     print("{} squared is {}".format(i, square(i)))
  • Python имеет встроенные функции, такие как print()и input(), но Python также позволяет создавать пользовательские функции
  1. def square(x):
  2.   return x * x
    • Это вызываемая функция square, которая принимает один аргумент xи возвращает значение x * x.
    • Подобно циклам, тело функции должно иметь отступ.
  1.  for i in range(10):
  2.  print("{} squared is {}".format(i, square(i)))
        • Этот цикл, который выводит результаты square с рядом аргументов, используя более старый метод для форматирования строк.
  • Попытка вызова функции, которая не была определена, вызовет  NameError исключение.

Модули

    • Модули — это отдельные .py файлы кода, часто написанные другими, которые используются в новом файле без перезаписи всего старого кода снова. Использование модулей позволяет, например, использовать функции в программе, размер которой превышает один файл.
    • Предполагая, что square функция в предыдущем примере была сохранена functions.py, добавление этой строки поверх нового модуля также позволит использовать там square.
  1. from functions import square
    • Если, например, в functions.py также включен пример цикла с демонстрацией square функции, этот цикл будет выполняться каждый раз при square импорте из functions, потому что интерпретатор Python считывает весь functions.py файл. Чтобы исправить это, код, который должен запускаться только при непосредственном запуске содержащего их файла, должен быть заключен в функцию, называемую, например  main,. После этого следует добавить следующее:
  1. if __name__ == "__main__":
  2.     main()

Это должно быть интерпретировано как «если этот файл в данный момент запускается», выполнить main.

Классы

  • Python class можно рассматривать как способ определения нового пользовательского типа данных Python, что несколько аналогично определению пользовательской функции.
  • Это создает новый class называется Point:
  1. class Point:
  2.     def __init__(self, x, y):
  3.      self.x = x
  4.      self.y = y
  5.  
  6.  p = Point(3, 5)
  7.  print(p.x)
  8.  print(p.y)
    • __init__  функция — специальная функция , которая определяет информацию, необходимую, когда новый Point будет создан. Self требуется всегда, что относится к создаваемому Point объекту, x и y являются его координатами.
    • self.x и self.y фактически выполняет работу по созданию x и y атрибутов Point и присваиванию передаваемых значений __init__.
    • По соглашению class имена обычно начинаются с заглавной буквы.
  • Это создает новый  Point со значениями  x = 3 и y = 5:
  1.  p = Point(3, 5)
    • Когда эта строка запускается, __init__ функция класса Point запускается автоматически.
  • Чтобы получить доступ к x атрибуту, используйте точечную запись:
  1. print(p.x)

Flask

  • HTTP (протокол передачи гипертекста) — это система, используемая в Интернете для взаимодействия и связи между компьютерами и серверами. Когда URL-адрес вводится в браузер, на сервер отправляется HTTP-запрос, который интерпретирует запрос и отправляет соответствующий HTTP-ответ, который, если все идет как положено, содержит запрошенную информацию, которая должна отображаться веб-браузером.
  • Методы HTTP:
    • GET. Браузер сообщает серверу, что желает получить информацию со страницы и просит отправить ее. Возможно, это самый распространенный метод.
    • HEAD. Браузер сообщает серверу, что желает получить информацию, но интересуется только заголовком, а не содержанием страницы. Приложение допускает запрос, в случае если GET был получен.
    • POST. Браузер сообщает серверу, что хочет запостить новую информацию по данному URL и сервер должен быть уверен, что сохранит ее и сделает один раз. Так обычно передается информация из HTML форм на сервер. Если присутствует GET, тогда HEAD будет добавлен автоматически.
    • PUT. Очень схоже с POST, но сервер может инициировать сохранение информации несколько раз, переписывая старые значения более одного раза. Вы можете задаться вопросом: «Для чего это нужно?». Есть несколько хороших причин, чтобы делать это таким образом. Учтите, что соединение может быть потеряно во время передачи: в этой ситуации система между браузером и сервером может затребовать передачу во второй раз. С POST это невозможно, так как запрос возможен только один раз.
    • DELETE. Удаление информации в полученной локации.
    • OPTIONS. Быстрый способ для клиента выяснить какой из методов поддерживается по данному URL. Начиная с Flask 0.6 эта возможность имплементирована автоматически. 
  • Приступив к разработке веб-сайтов, следующим шагом является написание кода, который отвечает за обработку на стороне сервера: получение и интерпретацию запросов и генерацию ответа для пользователя.
  • Код Flask обычно хранится внутри application.py, и может, например, выглядеть так:
  1. from flask import Flask # Import the class `Flask` from the `flask` module, written by someone else.
  2.  
  3. app = Flask(__name__) # Instantiate a new web application called `app`, with `__name__` representing the current file
  4.  
  5. @app.route("/") # A decorator; when the user goes to the route `/`, exceute the function immediately below
  6. def index():
  7.     return "Hello, world!"
    • Колба разработана с точки зрения маршрутов. Маршрут — это часть URL, которая определяет, какая страница запрашивается. Маршрут для страницы по умолчанию прост: /.
  • Чтобы запустить колбу, запустите ее flask run в каталоге, где application.py находится на веб-сервере flask. Flask распечатает URL-адрес, на котором работает сервер, и мы получим доступ к веб-сайту.
    • Если flask run выдает ошибку, попробуйте записать переменную среды и запустить export FLASK_APP=application.py чтобы указать  application.py как веб-сервер.

Flask и Jinja2

  1. @app.route("/&lt;string:name&gt;")
  2. def hello(name):
  3.   return f"Hello, {name}!"
  • Когда любая строка вводится как маршрут, она будет сохранена как name, что затем может быть использовано внутри декорированной функции.
  • Поскольку код Python отображает сайт, можно использовать все, на что способен Python. Например, name может быть написан с заглавной буквы перед отображением:
  1. name = name.capitalize()
  • HTML также может использоваться внутри возвращаемого значения:
  1. return f"<h1>Hello, {name}!</h1>"
  • Однако встроенный HTML не так полезен. Отдельные файлы HTML можно использовать так:
  1. from flask import Flask
  2.  
  3. app = Flask(__name__)
  4.  
  5. @app.route("/")
  6. def index():
  7.  return render_template("index.html")
  • index.html и любые другие файлы шаблона должны храниться в каталоге с именем templates.
  • Переменные могут быть определены как переменные Python  application.py и использоваться в шаблонах HTML, передавая их в качестве аргументов  render_template. Эти шаблоны отображаются с использованием отдельного языка шаблонов Jinja2:
  • В application.py:
  1. headline = "Hello, world!"
  2. return render_template("index.html", headline=headline)
  • В index.html:
  1. <h1>{{ headline }}</h1>
  • Jinja2 также допускает условные выражения:
  1. {% if new_year %}
  2.   <h1>Yes! Happy New Year!</h1>;
  3. {% else %}
  4.   <h1>No.</h1>;
  5. {% endif %}
  • Петли:
  1. {% for name in names %}
  2.     <li>{{ name }}</li>
  3. {$ endfor %}
  • В names должно быть что-то, что может быть зациклено, например, список Python.
  • Если на сервере Flask есть несколько маршрутов, то один маршрут может связываться с другим следующим образом:
  1. <a href="{{ url_for('more') }}">See more...</a>
  • more это имя функции, связанной с маршрутом.

Формы

  • С Flask и Jinja2 результаты HTML-форм теперь могут быть сохранены и использованы.
  • HTML-форма может выглядеть так:
  <form action="" method="post">
      <input type="text" name="name" placeholder="Enter Your Name">
      <button>Submit</button>
  <form>
    • action атрибут перечисляет маршрут , который должен быть «уведомлен» , когда форма была отправлена.
    • method атрибут, как запрос HTTP для отправки формы должен быть сделан. По умолчанию используется метод get, который делают браузеры при вводе URL. Однако, когда данные передаются, post их следует использовать.
    • name Атрибут ввода, а не новые, в настоящее время актуален, потому что можно ссылаться, когда форма была отправлена.
  • Код Python для обработки этой формы может выглядеть так:
  1. from flask import Flask, render_template, request
  2.  
  3. # some lines omitted here
  4.  
  5. @app.route("/hello", methods=["POST"])
  6. def hello():
  7.     name = request.form.get("name") # take the request the user made, access the form,
  8.                                     # and store the field called `name` in a Python variable also called `name`
  9.     return render_template("hello.html", name=name)
  • Маршрут /hello тот же, что hello указан в коде Jinja2. Этот маршрут также может принимать POST метод, который представляет собой способ отправки данных формы. Если для доступа к этому маршруту используется любой другой метод, возникнет ошибка Method Not Allowed.
    • Если существует несколько методов запроса, которые следует разрешить, то какой метод используется, можно проверить request.method, например, равным «GET» или «POST».

Сессии

  • Сессии — это то, как Flask может отслеживать данные, относящиеся к конкретному пользователю. Давайте для примера сделаем простое приложение для заметок. Пользователи должны видеть только свои заметки.
  • Чтобы использовать сеансы, они должны быть импортированы и настроены:
  1. from flask import Flask, render_template, request, session # gives access to a variable called `session`
  2.  # which can be used to keep vaules that are specific to a particular user
  3. from flask_session import Session # an additional extension to sessions which allows them
  4. # to be stored server-side
  5.  
  6. app.config["SESSION_PERMANENT"] = False
  7. app.config["SESSION_TYPE"] = "filesystem"
  8. Session(app)
  • Затем, предполагая, что есть некоторая HTML-форма, которая может отправить заметку, заметка может быть сохранена в месте, определенном для пользователя, используя его сеанс:
  1. @app.route("/", methods=["GET", "POST"])
  2. def index():
  3.  if session.get("notes") is None:
  4.    session["notes"] = []
  5.  if request.method == "POST":
  6.    note = request.form.get("note")
  7.  session["notes"].append(note)
  8.  
  9.  return render_template("index.html", notes=session["notes"])
  • notes это список, где будут храниться заметки. Если у пользователя еще нет списка заметок (проверено с помощью if session.get(«notes») is None), то ему выдается пустой список.
  • Если запрос подается через «POST» (то есть через форму), то примечание обрабатывается из формы так же, как и раньше.
  • Обработанная заметка, которая теперь называется переменной Python  note, добавляется в notes список. Этот список сам внутри  dict вызываемой session. У каждого пользователя есть уникальный session dict, а потому и уникальный notes список.
  • Наконец, notelist отображается путем перехода session[«notes»] к render_template.

Скачайте последний проект Session и попробуйте его запустить самостоятельно. Как установить Flask и создать первое приложение, смотрите ниже.

Установка Flask, первое приложение

Зависимости. Все необходимые дистрибутивы будут установлены автоматически при установке Flask.

    • Werkzeugреализует WSGI, стандартный интерфейс Python между приложениями и серверами.
    • Jinja— это язык шаблонов, который отображает страницы, которые обслуживает ваше приложение.
    • MarkupSafe поставляется с Jinja. Он избегает ненадежного ввода при рендеринге шаблонов, чтобы избежать инъекционных атак.
    • ItsDangerous надежно подписывает данные для обеспечения их целостности. Это используется для защиты сессионного куки Flask.
    • Click является основой для написания приложений командной строки. Он предоставляет flask команду и позволяет добавлять пользовательские команды управления.

Смотрите репозиторий Flask на GitHub с руководством по установке.

Видео из 2-х частей установки и создания первого приложения Flask:

Ссылка на исходный код проекта: https://github.com/drucoder/flask-sweater/tree/FlaskJinja (1) и https://github.com/drucoder/flask-sweater/tree/SqlAlchemy (2).

Ссылки Flask в видео устарели (используют версию 0.12), используйте новую версию (1.1):

Также можно посмотреть перевод статьи с официального сайта Flask “Quick Start” на сайте ru.wikibooks.org.

Дополнения: для установки нужна консоль bash. В Windows 7 нужно в командной строке ввести bash.

Также можно установить MinGW с официального сайта. После этого в Windows (при клике правой кнопкой мыши по пустому месту экрана) в выпадающем меню появится строка Git Bash Here.

Кликаем по ней и работаем в консоли bash.

Более подробно о запуске приложений Python можете почитать в статье «Запуск файлов Python на локальном сервере«.

В примере из видео используется реляционная база данных SQLAlchemy (посмотрите FlaskSQLAichemy), но можно использовать напрямую SQLite3, потому что этого достаточно для приложения такого размера. SQLAlchemy разумнее использовать для приложений большого размера, которая обрабатывает подключения к базе данных более разумным способом и дает много возможностей в обработке запросов. Кроме того, есть еще одна популярная нереляционная база данных — NoSQL, можно использовать и ее, если она вам больше подходит.

Также рекомендуем попробовать освоить мега-цикл из 18 статей (!) по Flask на сайте habr.com.

Читайте больше по теме:

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
Просмотры: 907

Популярные записи