Разное

Что такое фласка: Фласка орхидеи — альтернатива природному размножению орхидей

Содержание

Фласка орхидеи — альтернатива природному размножению орхидей

Фласка орхидеи — это не только популярный сувенир из Тайланда и некоторых других азиатских стран, но ещё и способ сэкономить при покупке орхидеи. Задумываетесь о покупке фласки с орхидеей, либо она уже у вас появилась, и вы не знаете, что с ней делать? На интересующие вас вопросы, вы найдете ответы в этой статье!

Фласка или говоря иными словами — колба, емкость, сосуд, банка. Фласки бывают из стека и пластика. Обязательное условие — прозрачные стенки.

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

Где купить фласки с орхидеями?
Фласки продают крупные разводчики орхидей, поставщики. Если вы живете недалеко от орхидейной фермы, вам не составит труда купить фласку с орхидеями. Но что если рядом нет таких ферм? Фласки — специфический продукт, вы не найдете их в обычном цветочном магазине. Можно попытать счастье в местных орхидейных теплицах. Так же есть специальные платформы-форумы, специализирующиеся на коллективных заказах орхидей из заграницы, на них вы сможете заказать фласку.

Мне вручили фласку — что с ней делать?
Часто в виде сувенира фласки орхидей привозят из Таиланда. Заказывали орхидею, а получили такой сюрприз! Не расстраивайтесь, мы научим вас с ними обращаться.

Осмотрите фласку со всех сторон. Если содержимое фласки перемешано, есть плесень на субстрате, нарушена герметичность или питательна среда на исходе — фласку надо немедленно вскрывать и высаживать содержимое. Так же высаживайте орхидейки, если они упираются макушкой в крышку ёмкости, и им уже некуда расти. В других случаях дайте сеянцам ещё подрасти, поставив фласку в светлое и тёплое место.

Вскрытие и высадка содержимого фласки
Вскрыть фласку из стекла или пластика с широким горлышком просто. Фласку из стекла с узким горлышком необходимо будет разбить. Будьте очень аккуратны, чтобы не порезаться и не повредить сеянцы орхидей.
Вскрыв фласку, промойте содержимое от питательной среды, просушите и высаживайте в маленькие горшочки под размер корневой. Субстратом для маленьких орхидеек может служить чистый мох или чистая кора мелкой и средней фракции или смесь коры с добавлением кокосовых чипсов и мха. Поставщики-тайцы и другие азиаты высаживают сеянцы орхидей в чистый мох, а европейские в чистую кору или в смеси. Всё зависит от личных предпочтений.

Уход за сеянцами орхидеи вне фласки
Количество сеянцев внутри фласки  варьируется от нескольких штук (3-5) до нескольких десятков. Высаженные сеянцы орхидей поместите в светлое и теплое место. Сеянцы очень нежные и болезненно переносят недостаток влаги, поэтому их поливают чаще взрослых орхидей. Не забывайте и об удобрениях, но делайте раствор удобрений намного слабее, чем для взрослых орхидей. Свет также играет не последнюю роль в росте орхидейных малышей, недостаток солнца компенсируйте подсветкой.

Через сколько зацветет орхидея из фласки?
Всё зависит от вида орхидейки и условий содержания. Благоприятные условия содержания приблизят вас к цветению, но не ждите его слишком быстро. Фаленопсис может зацвести на 2-3 году жизни. Каттлея через 5-7 лет, а то и больше. Пафиопедилум или «Венерин башмачек» тоже не поспешит вас обрадовать — до цветения пройдёт не менее 5-7, а иногда и 10 лет.

Не все готовы так долго ждать цветения. Поэтому, если вы хотите любоваться цветами — покупайте взрослую орхидею, готовую зацвести, или которая уже цвела.
Фласки интересны тем, кто хочет из семени вырастить взрослую орхидею. Наблюдать весь процесс развития орхидеи и дождаться цветения. Это трогательный и кропотливый труд, но плоды того стоят. Не бойтесь пробовать!

Следите за обновлениями в социальных сетях

Что это такое? Простое WSGI-приложение

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

Для тех кто не
совсем знаком с принципом взаимодействия между клиентом (браузером) и
фреймворком, установленном на сервере, опишу в двух словах этот процесс.

Когда
пользователь вводит в браузер строку запроса, например, vk.com, то от браузера
отправляется запрос к серверу, где расположен и работает этот сайт. Здесь мы
отложим в сторону вопрос маршрутизации и DNS-серверов,
сейчас это неважно, главное, что сеть Интернет так устроена, что маршрутизаторы
«знают» куда направлять запросы, если они относятся к работающим сайтам.

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

Но где же во
всей этой схеме фреймворк? В действительности он установлен на сервере. Так как
это обычный компьютер (ну может не совсем обычный, но принцип тот же), то на
нем установлено соответствующее программное обеспечение. Мы, опять же, не будем
здесь глубоко вдаваться в подробности, скажу лишь, что на них часто
устанавливают Linux-подобные ОС
(благодаря их надежности), затем программу под названием веб-сервер (часто это Apache или Nginx) и уже он
отдает обработку запроса конкретному фреймворку:

Здесь WSGI (Web Server Gateway Interface) — стандарт
взаимодействия между Python-программой, выполняющейся на
стороне сервера, и самим веб-сервером, например Apache. Фактически,
это интерпретатор Python, который запускает WSGI-приложение,
написанное на Flask.

При поступлении
запроса активизируется WSGI-приложение, выполняется определенный
обработчик, который еще называется «Представление» и реализованный в виде
функции на языке Python. Соответственно, если приходит сразу
несколько запросов, то одна и та же функция-обработчик может быть запущена в
параллельных потоках. Многопоточность – это норма для фреймворков, поэтому,
работая с представлениями во Flask, всегда следует это учитывать.

Конечно, в
рамках наших занятий мы не будем использовать удаленный сервер и устанавливать
на него данный фреймворк – это отдельная задача. Кстати, современные хостеры
предоставляют инструментарий для простой установки и настройки Flask. Поэтому этот
процесс не представляет больших сложностей. А для изучения данного пакета на
домашнем ПК от вас потребуется только его установить, используя установщик pip:

pip install Flask

Теперь мы можем
написать свое первое WSGI-приложение. В самом простом варианте
оно выглядит так:

from flask import Flask
 
app = Flask(__name__)
 
if __name__ == "__main__":
   app.run(debug=True)

Вначале идет
импорт класса Flask, который,
фактически и формирует это приложение. Далее, мы создаем экземпляр этого класса
и первым аргументом должны указать имя нашего приложения. Если вся программа
пишется в одном файле, то следует передавать директиву __name__, которая в
случае импорта будет содержать имя текущего файла, а в случае самостоятельного
запуска – значение «__main__». Для Flask это имеет
принципиальное значение, в частности, от этого зависит где искать подкаталоги с
шаблонами и статичными документами.

После этого
выполняется запуск фреймворка методом run и в качестве параметра
указывается debug=True, чтобы мы в браузере
видели все ошибки, которые будут возникать при разработке сайта-приложения. Конечно,
после его создания, здесь следует прописать debug=False, чтобы
случайные ошибки реальный пользователь уже не видел.

И, наконец,
условие. Зачем оно? Смотрите, когда мы непосредственно запускаем наш модуль, то
директива __name__ будет
принимать значение «__main__» и будет запущен локальный веб-сервер
для отладки текущего приложения. Если же модуль запускается, например, на
удаленном сервере, то нам не нужно запускать еще один сервер. В этом случае
директива __name__ будет
принимать имя данного модуля и строчка app.run выполнена не
будет. То есть, мы это условие прописали с целью запуска приложения
непосредственно на локальном устройстве.

Соответственно, как
только фреймворк запущен, у нас активизируется локальный веб-сервер и мы можем
в браузере создавать запрос, используя вот такой начальный адрес:

http://127.0.0.1:5000/

Давайте сделаем
это и посмотрим, что получится. Наберем в браузере указанный запрос и видим,
что запрашиваемая страница не найдена:

Все верно, так и
должно быть, так как мы в программе не создали еще ни одного представления.
Сделаем и это, добавим его:

@app.route("/")
def index():
    return "index"

Здесь
используется специальный декоратор route, который
создает обертку вокруг нашей функции index, которая будет
активизироваться при обращении к главной странице сайта, то есть, по запросу http://127.0.0.1:5000/

Запустим
программу, обновим страницу и теперь в браузере видим то, что возвратила
функция index:

Часто к главной
странице обращаются еще по index, то есть:

domain/index

например,

proproprogs.ru/index

Чтобы одну и ту
же страницу отобразить по нескольким URL-адресам, следует добавить
несколько конструкций route:

@app.route("/index")
@app.route("/")
def index():
    return "index"

Соответственно,
для любого другого адреса мы также можем добавить свой отдельный обработчик,
прописав еще один декоратор route:

@app.route("/about")
def about():
    return "<h2>О сайте</h2>"

Теперь на нашем
сайте как бы две страницы: главная и /about – о сайте. Причем,
наши обработчики возвращают HTML-документ и все теги будут
соответственно отображаться на странице в браузере.

Итак, на этом
занятии мы с вами сделали первые шаги в понимании работы Flask и построили
очень простое WSGI-приложение.





What the flask? / Хабр

Вообще-то, это картинка от wtforms, но у меня гимп почему-то не запускается.

Эту статью я пишу в баре. Очень хочется похоливарить, но бармен на меня смотрит круглыми глазами, а кальянщик просто улыбается и мотает головой.

Однажды, меня спросили: что плохого во flask? Тогда меня полностью устраивал этот милый фреймворк. Поработав с ним какое-то время, я написал все, что думаю, в рабочий слак, на что мне ответили: «Мурад, будь добрее». Вообще, я добрый и пушистый, но wtf?!

Стоит отметить, что я являюсь большим поклонником работы Армина. Его пакеты используются во многих мои проектах. А еще он невероятная заноза в сообществе Python. И это хорошо.

Flask

Flask — это обертка над очень крутыми обособленными проектами. Некоторые сравнивают его с джангой. Я хз почему.

Если попытаться описать все проблемы фласка в двух пунктах:

  1. импорты
  2. контекст реквеста

Все. Дальше можно не читать. Но если все еще не понятно, листаем дальше.

Blueprints

Если в джанге все приложения подключаются в INSTALLED_APPS, то во фласке используется концепция blueprints. Этакое приложение и обособленный неймспейс урлов в одном флаконе:

from flask import Flask
from yourapplication.simple_page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page, end_point='/simple_page')

Далее, можно роутить урлы так: url_for('simple_page.index').

Вложенность

А ее нет. Нельзя просто так взять и сделать вложенный неймспейс. В сети можно найти «решения», но здесь я буду рассматривать только коробочный фласк, потому что написать-то можно все.

Импорты

Когда вы делаете так в продакшен коде:

if foo == 3:
    do_stuff(foo)

Где-то в мире грущу я! Берегите меня, выносите это в сеттинги.

from myapp import app

class Foo(FlaskForm):
    choices = SelectField(choices=app.conf.FOO_CHOICES)

Концептуально. Но работать не будет. Потому что пару строчек назад мы импортировали пакет в myapp и навечно заказали себе путь туда.

Погодите, должен быть выход! Ага!

from flask import current_app

И это не работает. Потому что current_app доступен только в контектсте реквеста!

— Вынеси это наконец в файл сеттингов приложения, больной ублюдок! — голос из зала.

— А как я буду их подменять на проде или тестовом, а?

Кстати, для джанги на этот случай у меня есть специальная батарейка.

Просто представьте себе прекрасный дивный мир, где django.conf.settings доступен только в контексте реквеста!

flask.g

Нельзя не пошутить про одноименную точку. А главное, ее не нужно искать, она всегда тут: flask.g. Бада-бум-тсс!

Вот поэтому Армин — мой кумир!

В нее можно пробросить все необходимое:

@app.before_request
def before_request():
    g.locale = get_locale()
    g.foo = foo

Однако, это будет работать только в контексте реквеста, как и любые другие магические объекты фласка.

Роутинг урлов и их методы

У меня на сайте есть такой кусок урлов:

bp.add_url_rule('/api/v1/', view_func=ApiView.as_view('api_view'))
...
bp.add_url_rule('/<path:path>/', view_func=PageView.as_view('page_view'))

ApiView обрабатывает только один метод — POST. Угадайте, что будет если спросить GET? Ага, 404. Ее обеспечивает вторая вьюшка.

Чтобы получить NOT ALLOWED, нужно явно вернуть 405 в ApiView!

Fask, что с тобой не так?

Стейк!

А. Погодите. Это мне. Омн-омн-омн.

flask-wtf. CSRF

Ох. Допустим, нам нужно отключить проверку в одной вьюхе:

@app.route('/foo', methods=('GET', 'POST'))
@csrf.exempt
def my_handler():
    # ...
    return 'ok'

Значит, нам нужен app. Помните про импорты, да? Ищем выход, лезем в сорцы:

def exempt(self, view):
    ...
    if isinstance(view, string_types):
        view_location = view
    else:
        view_location = '.'.join((view.__module__, view.__name__))

    self._exempt_views.add(view_location)
    return view

Ура! Можно передать путь до вьюхи (в версии, которая вышла две недели назад)! Пробуем:

csrf.exempt('website.apps.typus_web.views.ApiView')

Не работает. На самом деле (ненавижу это выражение), мы подменили имя вьюхи, когда вызывали ApiView.as_view('api_view'):

csrf.exempt('website.apps.typus_web.views.api_view')

И «все равно», что мы указываем путь до объекта, которого нет. Работает! Не работает.

А знаете почему? Потому что форма. Она ничегошеньки не знает про вьюху:

class ApiForm(ViewForm):
    ...
    class Meta(ViewForm.Meta):
        csrf = False

Вот теперь работает.

url_for()

Допустим, вы хотите сделать так:

NAVIGATION = (
    (url_for('flatpages:index'), _('Home page')),
)

Забудьте. Вне контекста не работает. Наверное, можно сделать свой ленивый объект, в конце-концов, в джанге это тоже не сразу появилось.

flask-testing

Штука, призванная помочь с тестами. Например, можно заглянуть в контекст, который передается в шаблон. А давайте попробуем:

AssertionError: Popped wrong request context.

Ой. Что-то пошло не так. А знаете что? Я вот тоже не знаю.

На самом деле (ненавижу это выражение), я схватил NotImplementedError в одном из методов, которые не переопределил. Но поинт в том, что уронив тесты, вам ни за что не понять в чем причина.

Всякое разное

В процессе ковыряния фласка, нашел несколько моментов:

def jsonify(*args, **kwargs):
    ...
    if args and kwargs:
        raise TypeError('jsonify() behavior undefined when passed both args and kwargs')
    elif len(args) == 1:  # single args are passed directly to dumps()
        data = args[0]
    else:
        data = args or kwargs

Здесь что-то происходит. Это все, что я понимаю.

И это:

def make_response(*args):
    if not args:
        return current_app.response_class()
    if len(args) == 1:
        args = args[0]
    return current_app.make_response(args)

А теперь ягодки:

class Flask(_PackageBoundObject):
    def make_response(self, rv):
        status_or_headers = headers = None
        if isinstance(rv, tuple):
            rv, status_or_headers, headers = rv + (None,) * (3 - len(rv))

Все, жгите!

P.S. А чего я один эээ статьи пишу, м? Кто хочет на той неделе, скажем, во вторник (чтобы больше вместить) пойти в бар (в Питере, в районе Звездной)?.. Пишите в инбокс.

P.P.S. Хабр, ты почему не типографишь тексты? Вот, я даже штуку написал!

#3 Основы Flask ~ Уроки по Flask ~ PythonRu

Hello World во фреймворке Flask

Начать знакомство с Flask можно с создания простого приложения, которое выводит “Hello World”. Создаем новый файл main.py и вводим следующий код.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World'

if __name__ == "__main__":
    app.run()

Это приложение “Hello World”, созданное с помощью фреймворка Flask. Если код в main.py не понятен, это нормально. В следующих разделах все будет разбираться подробно. Чтобы запустить main.py, нужно ввести следующую команду в виртуальную среду Python.

(env) gvido@vm:~/flask_app$ python main.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Запуск файла main.py запускает локальный сервер для разработки на порте 5000. Осталось открыть любимый браузер и зайти на https://127.0.0.1:5000/, чтобы увидеть приложение Hello World в действии.

Остановить сервер можно с помощью комбинации CTRL+C.

Создание приложения Flask

У каждого Flask-приложения должен быть экземпляр класса. Экземпляр — это WSGI-приложение (WSGI – это интерфейс для взаимодействия сервера с фреймворком), которое показывает, что сервер передает все полученные запросы экземпляру для дальнейшей обработки. Объект класса Flask создается следующим образом:

from flask import Flask

app = Flask(__name__)

В первой строке класс Flask импортируется из пакета flask.

Во второй строке создается объект Flask. Для этого конструктору Flask назначается аргумент __name__. Конструктор Flask должен иметь один обязательный аргумент. Им служит название пакета. В большинстве случаев значение __name__ подходит. Название пакета приложения используется фреймворком Flask, чтобы находить статические файлы, шаблоны и т. д.

Создание route (путей)

Маршрут (или путь) используется во фреймворке Flask для привязки URL к функции представления. Эта функция отвечает на запрос. Во Flask декоратор route используется, чтобы связать URL адрес с функций. Вот как маршрут создается.

@app.route('/')
def index():
    return 'Hello World'
Подписывайтесь на телеграм каналы

Этот код назначает функцию index() обработчиком корневого URL в приложении. Другими словами, каждый раз, когда приложение будет получать запрос, где путь — /, вызывается функция index(), и на этом запрос завершается.

Как вариант можно использовать метод add_url_rule() вместо декоратора route для маршрутизации. add_url_rule() — это простой метод, а не декоратор. Помимо URL он принимает конечную точку и название функции представления. Конечная точка относится к уникальному имени маршрута. Обычно, название функции представления — это и есть конечная точка. Flask может генерировать URL из конечной точки, но об этом позже. Предыдущий код аналогичен следующему:

def index():
    return 'Hello World'

app.add_url_rule('/', 'index', index)

Декоратор route используется в большинстве случаев, но у add_url_rule() есть свои преимущества.

Функция представления должна вернуть строку. Если пытаться вернуть что-то другое, сервер ответит ошибкой 500 Internal Sever Error.

Можно создать столько столько, сколько нужно приложению. Например, в следующем списке 3 пути.

@app.route('/')
def index():
    return 'Home Page'

@app.route('/career/')
def career():
    return 'Career Page'

@app.route('/feedback/')
def feedback():
    return 'Feedback Page'

Когда URL в маршруте заканчивается завершающим слешем (/), Flask перенаправляет запрос без слеша на URL со слешем. Так, запрос к /career будет перенаправлен на /career/.

Для одной функции представления может быть использовано несколько URL. Например:

@app.route('/contact/')
@app.route('/feedback/')
def feedback():
    return 'Feedback Page'

В этом случае в ответ на запросы /contact/ или /feedback/, будет вызвана функция feedback().

Если перейти по адресу, для которого нет соответствующей функции представления, появится ошибка 404 Not Found.

Эти маршруты статичны. Большая часть современных приложений имеют динамичные URL. Динамичный URL – это адрес, который состоит из одной или нескольких изменяемых частей, влияющих на вывод страницы. Например, при создании веб-приложения со страницами профилей, у каждого пользователя будет уникальный id. Профиль первого пользователя будет на странице /user/1, второго — на /user/2 и так далее. Очень неудобный способ добиться такого результата — создавать маршруты для каждого пользователя отдельно.

Вместе этого можно отметить динамические части URL как <variable_name> (переменные). Эти части потом будут передавать ключевые слова функции отображения. Следующий код демонстрирует путь с динамическим элементом.

@app.route('/user/<id>/')
def user_profile(id):
    return "Profile page of user #{}".format(id)

В этом примере на месте <id> будет указываться часть URI, которая идет после /user/. Например, если зайти на /user/100/, ответ будет следующим.

Profile page of user #100

Этот элемент не ограничен числовыми id. Адрес может быть /user/cowboy/, /user/foobar10/, /user/@@##/ и так далее. Но он не будет работать со следующими URI: /user/, /user/12/post/. Можно ограничить маршрут, чтобы он работал только с числовыми id после /user/. Это делается с помощью конвертера.

По умолчанию динамические части URL передаются в функцию в виде строк. Это можно изменить с помощью конвертера, который указывается перед динамическими элементами URL с помощью <converter:variable_name>. Например, /user/<int:id>/ будет работать с адресами /user/1/, /user/200/ и другими. Но /user/cowboy/, /user/foobar10/ и /user/@@##/ не подойдут.

В этом списке все конвертеры, доступные во Flask:

КонвертерОписание
stringпринимает любые строки (значение по умолчанию).
intпринимает целые числа.
floatпринимает числа с плавающей точкой.
pathпринимает полный путь включая слеши и завершающий слеш.
uuidпринимает строки uuid (символьные id).

Запуск сервера

Для запуска сервера разработки нужно использовать метод run() объекта Flask.

if __name__ == "__main__":
    app.run()

Условие __name__ == "__main__" гарантирует, что метод run() будет вызван только в том случае, если main.py будет запущен, как основная программа. Если попытаться использовать метод run() при импорте main.py в другой модуль Python, он не вызовется.

Важно: сервер разработки Flask используется исключительно для тестирования, поэтому его производительность невысокая.

Теперь должно быть понятнее, как работает main.py.

Режим отладки (Debug)

Баги неизбежны в программировании. Поэтому так важно знать, как находить ошибки в программе и исправлять их. Во Flask есть мощный интерактивный отладчик, который по умолчанию отключен. Когда он выключен, а в программе обнаруживается ошибка, функция показывает 500 Internal Sever Error. Чтобы увидеть это поведение наглядно, можно специально добавить баг в файл main.py.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    print(i)
    return 'Hello World'
    
if __name__ == "__main__":
    app.run()

В этом случае программа пытается вывести значение неопределенной переменной i, что приводит к ошибке. Если открыть https://127.0.0.1:5000/, то появится ошибка 500 Internal Sever Error:

Тем не менее сам браузер не сообщает о типе ошибки. Если посмотреть в консоль, то можно увидеть отчет об ошибке. В данном случае он выглядит вот так:

File "/home/gvido/flask_app/env/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/gvido/flask_app/env/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "main.py", line 13, in index
    print(i)
NameError: name 'i' is not defined

Когда режим отладки выключен, после изменения кода нужно каждый раз вручную запускать сервер, чтобы увидеть изменения. Но режим отладки будет перезапускать его после любых изменений в коде.

Чтобы включить режим, нужно передать аргумент debug=True методу run():

if __name__ == "__main__":
    app.run(debug=True)

Еще один способ — указать значение True для атрибута debug.

from flask import Flask

app = Flask(__name__)
app.debug = True

После обновления файл main.py следующим образом его можно запускать.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    print(i)
    return 'Hello World'

if __name__ == "__main__":
    app.run(debug=True) 

Теперь при открытии https://127.0.0.1:5000/ на странице будет отладчик.

Теперь, когда отладчик включен, вместо ошибки 500 Internal Server на странице будет отображаться отчет об ошибке. Он в полной мере описывает, какая ошибка случилась. Внизу страницы видно, что оператор print пытался вывести значение неопределенной переменной i. Там же указан тип ошибки, NameError, что подтверждает то, что ошибка заключается в том, что имя i не определено.

Кликнув на строчку кода на странице вывода ошибки, можно получить исходный код, где эта ошибка обнаружена, а также предыдущие и следующие строчки. Это помогает сразу понять контекст ошибки.

При наведении на строчку кода отображается иконка терминала. Нажав на нее, откроется консоль, где можно ввести любой код Python.

В ней можно проверить локальные переменные.

Если консоль открывается первый раз, то нужно ввести PIN-код.

Это мера безопасности, призванная ограничить доступ к консоли неавторизованным пользователям. Посмотреть код можно в консоли при запуске сервера. Он будет указан в начале вывода.

Завершить урок стоит созданием еще одного приложения Flask с применением всех имеющихся знаний.

Создаем еще один файл main2.py со следующим кодом:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello Flask'

@app.route('/user/<int:user_id>/')
def user_profile(user_id):
    return "Profile page of user #{}".format(user_id)

@app.route('/books/<genre>/')
def books(genre):
    return "All Books in {} category".format(genre)

if __name__ == "__main__":
    app.run(debug=True)

Если запустить файл и зайти на https://127.0.0.1:5000/, браузер поприветствует выражением «Hello Flask»:

В этой новой версии приложения есть два динамических пути. Если в браузере ввести https://127.0.0.1:5000/user/123/, откроется страница со следующим содержанием:

Стоит заметить, что путь /user/<int:user_id>/ будет работать только с теми URL, где динамическая часть (user_id) представлена числом.

Чтобы проверить второй динамический путь, нужно открыть https://127.0.0.1:5000/books/sci-fi/. В этот раз получится следующее:

Если сейчас попробовать открыть URL, который не определен в путях, выйдет ошибка 404 Not Found. Например, такой ответ получите при попытке перейти на https://127.0.0.1:5000/products.

Как Flask обрабатывает запрос?

Откуда Flask знает, какую функцию выводить, когда он получает запрос от клиента?

Flask сопоставляет URL и функции отображения, которые будут выводиться. Определение соответствий (маршрутизация) создается с помощью декоратора route или метода add_url_rule() в экземпляре Flask. Получить доступ к этим соответствиям можно с помощью атрибута url_map у экземпляра Flask.

>>>
>>> from main2 import app
>>> app.url_map
Map([<Rule '/' (OPTIONS, GET, HEAD) -> index>,
 <Rule '/static/<filename>' (OPTIONS, GET, HEAD) ->  static>,
 <Rule '/books/<genre>' (OPTIONS, GET, HEAD) ->  books>,
 <Rule '/user/<user_id>' (OPTIONS, GET, HEAD) ->  user_profile>])
>>>

Как видно, есть 4 правила. Flask определяет соответствия URL в следующем формате:

url pattern, (comma separated list of HTTP methods handled by the route) -> view function to execute

Путь /static/<filename> автоматически добавляется для статических файлов Flask. О работе со статическими файлами речь пойдет в отдельном уроке «Обслуживание статических файлов во Flask».

Мега-Учебник Flask, Часть 1: «Привет, Мир!» / Хабр

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

Здесь список всех статей в серии:
Часть 1: Привет, Мир!
Часть 2: Шаблоны
Часть 3: Формы
Часть 4: База данных
Часть 5: Вход пользователей
Часть 6: Страница профиля и аватары
Часть 7: Unit-тестирование
Часть 8: Подписчики, контакты и друзья
Часть 9: Пагинация
Часть 10: Полнотекстовый поиск
Часть 11: Поддержка e-mail
Часть 12: Реконструкция
Часть 13: Дата и время
Часть 14: I18n and L10n
Часть 15: Ajax
Часть 16: Отладка, тестирование и профилирование
Часть 17: Развертывание на Linux (даже на Raspberry Pi!)
Часть 18: Развертывание на Heroku Cloud

Моя предыстория

Я разработчик ПО с двузначным числом лет опыта разработки комплексных приложений на нескольких языках. Впервые я познакомился с Python для создания привязок к C++ библиотеке на работе. Вдобавок к Python, я писал веб-приложения на PHP, Ruby, Smalltalk и, верите вы или нет, еще на С++. Из всего этого, я нахожу комбинацию Python/Flask самой гибкой.

Приложение

Приложение, которое я собираюсь разрабатывать как часть этого руководства, является сервером микроблогов, и я решил назвать его microblog. Довольно креативно, я знаю.

Во время нашего прогресса я затрону следующие темы:

  • Управление пользователями, включая управление входами, сессиями, ролями пользователя, профилями и пользовательскими аватарами
  • Управление базой данных, включая миграцию
  • Поддержка форм, включая валидацию полей
  • Пагинация длинных списков элементов
  • Полнотекстовый поиск
  • E-mail уведомления пользователей
  • HTML шаблоны
  • Поддержка нескольких языков
  • Кеширование и другая оптимизация производительности
  • Методы отладки для серверов разработки и продакшна
  • Установка на продакшн сервер

Как видите, я весьма значительно берусь за все это. Надеюсь, что это приложение, когда я его закончу, станет чем-то вроде шаблона для написания других веб-приложений.

Требования

Если ваш компьютер поддерживает Python 2.6/2.7, то все, вероятно, пойдет хорошо. Приложение из руководства должно нормально работать на Windows, OS X и Linux.

Это руководство подразумевает, что вы знакомы с окном терминала (командной консолью в случае Windows), и вы знаете основные команды для работы с файлами вашей ОС. Если это не так, то перед тем как продолжить, я рекомендую вам ознакомиться с тем, как создавать директории, копировать файлы и т.д., используя консоль.

Наконец, вы должны чувствовать себя свободно в написании кода на Python. Знакомство с модулями и пакетами этого языка также не помешает.

Установка Flask

Ну что ж, приступим!
Если у вас еще не установлен Python 2.7, то берем его отсюда.

Теперь нам нужно установить Flask и несколько расширений, которые мы будем использовать. Я предпочитаю создание виртуального окружения, где все это будет установлено таким образом, что ваша основная установка Python затронута не будет. В качестве бонуса, вам не нужен будет root доступ для установки таким способом.

Итак, открываем терминал, выбираем место, где будет ваше приложение, и создаем новую папку, в которой оно будет содержаться. Назовем эту папку microblog.

Далее скачиваем virtualenv.py и кладем его внутрь новой папки.

Чтобы создать новое окружение введите следующую команду:

python virtualenv.py flask

Эта команда создаст полноценное окружение Python внутри папки flask

Виртуальные окружения могут быть активированы и деактивированы по желанию. Активированное окружение добавляет путь своей папки bin в path системы, например, когда вы вызываете интерпретатор python, то получаете версию текущего окружения, а не системную. Лично я никогда не любил это свойство, поэтому ни разу не активировал ни одно из моих окружений, вместо этого я просто вызывал тот интерпретатор, который хотел, печатая его путь.

Прим. пер.: Перед тем как вы начнете вводить команды, хочу отметить, что в комментариях к девятой части отметится баг в flask-whooshalchemy, исправленную версию можнонужно скачать отсюда (репозиторий автора)

Если вы пользователь Linux, OS x или Cygwin, установите flask и расширения, вводя следующие команды одну за одной:

Список команд

flask/bin/pip install flask==0.9
flask/bin/pip install flask-login
flask/bin/pip install flask-openid
flask/bin/pip install flask-mail
flask/bin/pip install sqlalchemy==0.7.9
flask/bin/pip install flask-sqlalchemy==0.16
flask/bin/pip install sqlalchemy-migrate
flask/bin/pip install flask-whooshalchemy==0.54a
flask/bin/pip install flask-wtf==0.8.4
flask/bin/pip install pytz==2013b
flask/bin/pip install flask-babel==0.8
flask/bin/pip install flup

Если же вы пользователь Windows, то команды слегка отличаются:
Список команд

flask\Scripts\pip install flask==0.9
flask\Scripts\pip install flask-login
flask\Scripts\pip install flask-openid
flask\Scripts\pip install sqlalchemy==0.7.9
flask\Scripts\pip install flask-sqlalchemy==0.16
flask\Scripts\pip install sqlalchemy-migrate
flask\Scripts\pip install flask-whooshalchemy==0.54a
flask\Scripts\pip install flask-wtf==0.8.4
flask\Scripts\pip install pytz==2013b
flask\Scripts\pip install flask-babel==0.8
flask\Scripts\pip install flup

Эти команды скачают и установят все пакеты, которые мы будем использовать в нашем приложении.
Учтите, что мы собираемся использовать Flask 0.9, а не последнюю версию. Flask 0.10 не было довольно долго и некоторые расширения не готовы для работы с данной версией. Также есть несколько несовместимостей между пакетами и последней версией pip, которые решены использованием конкретных версий для установки.

Windows пользователей ждет еще один шаг. Наблюдательный читаель заметит, что в списке команд для Windows отсутствует flask-mail. Это расширение не устанавливается чисто на Windows, поэтому мы пойдем обходным путем:

flask\Scripts\pip install --no-deps lamson chardet flask-mail

Я не буду вдаваться в подробности, поэтому если вы хотите узнать больше, прочтите документацию к flask-mail.

Если установка всех пакетов прошла успешно, вы можете удалить virtualenv.py, поскольку файл нам больше не понадобится.

«Hello, World!» в Flask

Теперь у вас есть подпапка flask, в вашей папке microblog, содержащая интерпретатор Python и фреймворк Flask с расширениями, которые мы будем использовать в этом приложении. Настало время написать наше первое веб-приложение!

После того как вы переместились папку microblog, давайте создадим основную структуру папок для нашего приложения:

mkdir app
mkdir app/static
mkdir app/templates
mkdir tmp

В папку app мы поместим само наше приложение. Подпапка static нужна для хранения статики, такой как картинки, javascript файлы и таблицы стилей. Подпапка templates, очевидно, предназначена для хранения наших шаблонов.

Давайте начнем с создания простого скрипта инициализации нашего пакета app (файл app/__init__.py)

from flask import Flask

app = Flask(__name__)
from app import views

Скрипт выше просто создает объект приложения (наследуя Flask), затем импортирует модуль представлений, который мы еще не написали.

Представления — это обработчики, которые отвечают на запросы веб-браузера. Представления в Flask пишутся как Python функции. Каждая функция представления сопоставляется с одним или несколькими запросами URL.

Напишем нашу первую функцию представления (файл app/views.py)

from app import app

@app.route('/')
@app.route('/index')
def index():
    return "Hello, World!"

Это весьма простое представление, которое просто возвращает строку для отображения в пользовательском браузере. Два декоратора route создают привязку адресов / и /index к этой функции.

Последним шагом для получения полностью работающего веб-приложения будет создание скрипта, который стартует веб-сервер нашего приложения. Давайте назовем скрипт run.py и положим его в корневой каталог (microblog/):

#!flask/bin/python
from app import app
app.run(debug = True)

Скрипт просто импортирует переменную app из нашего пакета app и вызывает метод run для того, чтобы запустить сервер. Помните, что переменная app — экземпляр класса Flask, мы создали его выше.

Для запуска вашего приложения просто запустите скрипт. На OS X, Linux и Cygwin вам следует пометить файл исполняемым перед тем как вы сможете его запустить.

chmod a+x run.py

Тогда скрипт может быть вызван просто:

./run.py

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

flask/Scripts/python run.py

После старта сервер будет прослушивать порт 5000, ожидая соединений. Теперь откроем браузер и введем следующий URL в адресную строку:

Или же вы можете использовать эту ссылку:

http://localhost:5000/index

Теперь вы увидели маршрутизацию в действии? Первый URL привязан к /, в то время как второй к /index. Оба маршрута ассоциированы с нашей функцией представления, поэтому они дают одинаковый результат. Если вы введете любой другой маршрут, то получите ошибку, так как только эти два были привязаны к функции представления.

Когда вы закончите играть с сервером вы можете просто нажать Ctrl-C, чтобы остановить его.

И этим я хочу закончить первую часть этого руководства.

Те из вас, кто поленился печатать, могут скачать код из этого руководства ниже:

Скачать microblog-0.1.zip.

Обратите внимание, что вам нужно установить Flask, чтобы запустить приложение из архива выше.

Что дальше

В следующей части серии мы изменим наше маленькое приложение для использования HTML шаблонов.

Надеюсь увидимся в следующей части.

Мигель

Привет, мир! ( издание 2018 ) / Хабр

blog.miguelgrinberg.com

Miguel Grinberg


>>> следующая глава >>>

Эта статья является переводом нового издания учебника Мигеля Гринберга. Прежний перевод давно утратил свою актуальность.

Автор планирует завершить его выпуск в мае 2018. Я, со своей стороны, постараюсь не отставать с переводом.

Для справки ниже приведен список статей этой серии.

Новый учебник написан в 2017 году, и, наконец, он выглядит так, как если бы он был настроен на версию Python 3. Решены проблемы с совместимостью, изменен фокус в сторону Python 3, а не Python 2 как было в 2012 году в прежней версии учебника.

К сожалению, Python 2 или 3 — это не единственное, что изменилось. Есть также несколько технологий, которые имели смысл в 2012 году, но теперь устарели. К ним относятся:

  • Механизм аутентификации OpenID, который больше не поддерживается многими провайдерами.
  • Пакет sqlalchemy-migrate для миграции баз данных, который, похоже, так же потерял поддержку сообщества. В эти дни Alembic — намного более лучший выбор для миграции чем SQLAlchemy.
  • Интерфейс командной строки Flask (Flask Shell), который в то время не существовал, а теперь является незаменимым инструментом разработчика.
  • В то время, когда Мигель начал работать над учебником, Flask blueprints были слишком новыми, поэтому он решил не использовать эту функцию. В 2017 году blueprints являются обязательными для применения в Flask.
  • Bootstrap 2 для стилизации и форматирования веб-страниц, теперь имеет две основные версии. Новые версии Bootstrap не имеют обратной совместимости с версией 2.
  • Изменения в сервисе Heroku, инструкции по развертыванию которые представлены учебнике устарели.

Многие вещи, которые изменились за эти пять лет, в основном означают, что нужно пересмотреть все главы, причем большинство из них претерпели довольно важные изменения.

Сам Мигель считает, что вырос профессионально за эти пять лет, и думает, что сможет принести гораздо большую ценность этому учебнику с этим новым опытом. После выхода первого учебника он провел более дюжины конференций и выпустил кучу учебных пособий, написал очень успешную книгу разработки Flask для крупного издательства, создал несколько популярных проектов с открытым исходным кодом .

Кроме того, у Мигеля есть еще пять лет опыта работы в качестве технического блоггера, так как продолжал создавать контент для своего блога на протяжении всех этих лет. Весь этот опыт будет отражен в обновлениях, которые он приводит в учебнике.

Более подробно читайте в блоге Мигеля

VIDEO

Добро пожаловать!

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

Примечание 1: Если вы ищете старые версии данного курса, это здесь.

Примечание 2: Если вдруг Вы хотели бы выступить в поддержку моей(Мигеля) работы в этом блоге, я (Мигель Гринберг) предлагаю полную версию данного руководства упакованную электронную книгу или видео. Для получения более подробной информации посетите learn.miguelgrinberg.com.

Все примеры кода представленные в этом учебном курсе, размещены на GitHub. Загрузка кода из GitHub поможет вам сэкономить время, но я настоятельно рекомендую набирать код самостоятельно, по крайней мере, первые несколько глав. После того, как вы станете ближе знакомы с Flask можно получить доступ к коду прямо из GitHub, только в том случае, если ввод становится слишком утомительным.

В начале каждой главы, я дам вам три GitHub ссылки, которые могут быть полезны при изучении главы. Browse откроет GitHub репозиторий для микроблога в том месте, где собраны изменения к главе, которую Вы читаете, за исключением любых изменений, внесенных в будущих главах. Zip — это ссылка для загрузки zip-архива, в том числе приложения и изменений в главе. Diff — откроет графическое представление всех изменений, внесенных в главу, которую Вы собираетесь читать.

На GitHub ссылки в этой главе: Browse, Zip, Diff.

Установка Python

Если на вашем компьютере не установлен Python, установите его. Если ваша операционная система не имеет предустановленный пакет Python, вы можете скачать программу установки с официального сайта Python. Если вы используете Microsoft Windows вместе с WSL или Cygwin, обратите внимание, что вы не будете использовать родную версию Python для Windows, а версию, совместимую с Unix, которую вам нужно получить от Ubuntu (если вы используете WSL) или от Cygwin.

Чтобы убедиться, что ваша установка Python является функциональной, вы можете открыть окно терминала и ввести python3, или если это не работает, просто python. Вот что вам следует ожидать:

$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> _

или так в cmd (окно командной строки Microsoft Windows) :

c:\cp>c:\python33\python
Python 3.3.5 (v3.3.5:62cf4e77f785, Mar  9 2014, 10:37:12) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Интерпретатор Python теперь находится в ожидании пользовательского ввода. В будущих главах вы узнаете, для чего это интерактивное приглашение полезно. Но пока Вы подтвердили, что Python установлен в вашей системе. Чтобы выйти из интерактивного приглашения, вы можете ввести exit() и нажать Enter.

В версиях Python для Linux и Mac OS X вы также можете выйти из интерпретатора, нажав Ctrl-D.

В Windows, комбинация клавиш для выхода — Ctrl-Z, затем Enter.

Установка Flask

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

В Python пакеты, такие как Flask, доступны в общем репозитории, откуда их можно загрузить и установить. Официальный репозиторий пакетов Python называется PyPI, что означает Python Package Index (также известный, как «cheese shop»). Установка пакета из PyPI очень проста, потому что у Python есть инструмент под названием pip, который выполняет эту работу (в Python 2.7 pip не входит в комплект с Python и его нужно устанавливать отдельно).

Чтобы установить пакет на свой компьютер, вы используете pip следующим образом:

$ pip install <package-name>

Интересно, что этот метод установки пакетов не будет работать в большинстве случаев. Если ваш интерпретатор Python был установлен глобально для всех пользователей вашего компьютера, велика вероятность того, что ваша обычная учетная запись пользователя не получит разрешения на внесение в нее изменений, поэтому единственный способ выполнить вышеприведенную команду — запустить ее от имени администратора. Но даже без этого осложнения поймите, что происходит, когда вы устанавливаете пакет, как указанным выше способом. Инструмент pip загрузит пакет из PyPI, а затем добавит его в вашу папку Python. С этого момента каждый скрипт Python, который у вас есть в вашей системе, будет иметь доступ к этому пакету. Представьте ситуацию, когда вы закончили веб-приложение с использованием версии 0.11 Flask, которая была самой последней версией Flask при запуске, но теперь она была заменена версией 0.12. Теперь вы хотите запустить второе приложение, для которого вы хотели бы использовать версию 0.12, но если вы замените установленную версию 0.11, вы рискуете сломать свое старое приложение. Вы видите проблему? Было бы идеально, если бы можно было установить Flask 0.11, который будет использоваться вашим старым приложением, а также установить Flask 0.12 для Вашего нового.

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

Начнем с создания каталога, в котором будет жить проект. Я собираюсь назвать этот каталог microblog, так как это имя приложения:

$ mkdir microblog
$ cd microblog

Если вы используете версию Python 3, в нее включена поддержка виртуальной среды, поэтому все, что вам нужно сделать для ее создания, это:

$ python3 -m venv venv

С помощью этой команды Python запустит пакет venv, который создает виртуальную среду с именем venv. Первым venv в команде является имя пакета виртуальной среды Python, а второе — имя виртуальной среды, которое я буду использовать для этой конкретной среды. Если вы считаете, что это сбивает с толку, вы можете заменить второй venv другим именем, которое вы хотите назначить своей виртуальной среде. В общем, я создаю свои виртуальные среды с именем venv в каталоге проекта, поэтому всякий раз, когда я подключаюсь к проекту, я нахожу его соответствующую виртуальную среду.

Обратите внимание, что в некоторых операционных системах вам может понадобиться использовать python вместо python3 в приведенной выше команде. Некоторые установки используют python для релизов Python 2.x и python3 для релизов 3.x, в то время как другие отображают python в выпусках 3.x.

По завершении команды вы будете иметь каталог с именем venv, где хранятся файлы виртуальной среды.

Если вы используете любую версию Python старше 3.4 (включая выпуск 2.7), виртуальные среды не поддерживаются изначально. Для этих версий Python вам необходимо загрузить и установить сторонний инструмент virtualenv, прежде чем создавать виртуальные среды. После того, как virtualenv установлен, вы можете создать виртуальную среду со следующей командой:

$ virtualenv venv

или так

$ python virtualenv.py venv

Прим.переводчика: У меня установлено несколько версий Python. Я использую Python3.3. В моем случае пришлось вводить строку так:

C:\microblog>c:\Python33\python.exe c:\Python33\Lib\site-packages\virtualenv.py venv

В полученном сообщении видно, что установлен pip и ряд пакетов:

Using base prefix 'c:\\Python33'
New python executable in C:\microblog\venv\Scripts\python.exe
Installing setuptools, pip, wheel...done.

Независимо от метода, который вы использовали для его создания, вы создали свою виртуальную среду. Теперь вам нужно сообщить системе, что вы хотите ее использовать, активируя ее. Чтобы активировать новую виртуальную среду, используете следующую команду:

$ source venv/bin/activate
(venv) $ _

Если вы используете cmd (окно командной строки Microsoft Windows), команда активации немного отличается:

$ venv\Scripts\activate
(venv) $ _

Когда вы активируете виртуальную среду, конфигурация сеанса терминала изменяется так, что интерпретатор Python, хранящийся внутри нее, станет тем, который вызывается при вводе python. Кроме того, в запросе терминала включено имя активированной виртуальной среды. Изменения, внесенные в сеанс терминала, являются временными и частными для этого сеанса, поэтому они не будут сохраняться при закрытии окна терминала. Если вы одновременно работаете с несколькими терминальными окнами, отлично видно, чтобы на каждом из них были задействованы разные виртуальные среды.

Теперь, когда вы создали и активировали виртуальную среду, вы можете, наконец, установить в нее Flask:

(venv) C:\microblog>pip install flask
Collecting flask
  Using cached Flask-0.12.2-py2.py3-none-any.whl
Requirement already satisfied: click>=2.0 in c:\python33\lib\site-packages (from flask)
Requirement already satisfied: Werkzeug>=0.7 in c:\python33\lib\site-packages (from flask)
Requirement already satisfied: Jinja2>=2.4 in c:\python33\lib\site-packages (from flask)
Requirement already satisfied: itsdangerous>=0.21 in c:\python33\lib\site-packages (from flask)
Requirement already satisfied: markupsafe in c:\python33\lib\site-packages (from Jinja2>=2.4->flask)
Installing collected packages: flask
Successfully installed flask-0.12.2

(venv) C:\microblog>

Если вы хотите проверить, что в вашей виртуальной среде установлен Flask, вы можете запустить интерпретатор Python и импортировать Flask в него:

(venv) C:\microblog>python
Python 3.3.5 (v3.3.5:62cf4e77f785, Mar  9 2014, 10:37:12) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import flask
>>>

Если этот импорт не дает вам никаких ошибок, вы можете поздравить себя, так как Flask установлен и готов к использованию.

Flask приложение «Привет, мир»

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

Приложение будет существовать в виде пакета.

Прим.переводчика: Пакет — это коллекция модулей.

В Python подкаталог, содержащий файл __init__.py, считается пакетом и может быть импортирован. Когда вы импортируете пакет, __init__.py выполняет и определяет, какие символы предоставляют пакет для внешнего мира.

Давайте создадим пакет под названием app, в котором будет размещено приложение. Убедитесь, что вы находитесь в каталоге microblog, а затем выполните следующую команду:

(venv) $ mkdir app

__init__.py для пакета приложения будет содержать следующий код:

from flask import Flask

app = Flask(__name__)

from app import routes

Сценарий выше просто создает объект приложения как экземпляр класса Flask, импортированного из пакета flask. Переменная __name__, переданная в класс Flask, является предопределенной переменной Python, которая задается именем модуля, в котором она используется. Flask использует расположение модуля, переданного здесь как отправную точку, когда ему необходимо загрузить связанные ресурсы, такие как файлы шаблонов, которые я расскажу в главе 2. Для всех практических целей передача __name__ почти всегда будет настраивать flask в правильном направлении. Затем приложение импортирует модуль routes, который еще не существует.

Один из аспектов, который может показаться запутанным вначале, состоит в том, что существуют два объекта с именем app. Пакет приложения определяется каталогом приложения и сценарием __init__.py и указан в инструкции routes импорта приложения. Переменная app определяется как экземпляр класса Flask в сценарии __init__.py, что делает его частью пакета приложения.

Другая особенность заключается в том, что модуль routes импортируется внизу, а не наверху скрипта, как это всегда делается. Нижний импорт является обходным путем для циклического импорта, что является общей проблемой при использовании приложений Flask. Вы увидите, что модуль routes должен импортировать переменную приложения, определенную в этом скрипте, поэтому, поместив один из взаимных импортов внизу, вы избежите ошибки, которая возникает из взаимных ссылок между этими двумя файлами.

Так что же входит в модуль routes? routes — это разные URL-адреса, которые приложение реализует. В Flask обработчики маршрутов приложений записываются как функции Python, называемые функциями просмотра. Функции просмотра сопоставляются с одним или несколькими URL-адресами маршрутов, поэтому Flask знает, какую логику следует выполнять, когда клиент запрашивает данный URL-адрес.

Вот ваша первая функция просмотра, которую вам нужно написать в новом модуле с именем app/routes.py:

from app import app

@app.route('/')
@app.route('/index')
def index():
    return "Hello, World!"

Эта функция просмотра на самом деле довольно проста, она просто возвращает приветствие в виде строки. Две странные строки @app.route над функцией — декораторы, уникальная особенность языка Python. Декоратор изменяет функцию, которая следует за ней. Общий шаблон с декораторами — использовать их для регистрации функций как обратных вызовов для определенных событий. В этом случае декоратор @app.route создает связь между URL-адресом, заданным как аргумент, и функцией. В этом примере есть два декоратора, которые связывают URL-адреса / и /index с этой функцией. Это означает, что когда веб-браузер запрашивает один из этих двух URL-адресов, Flask будет вызывать эту функцию и передавать возвращаемое значение обратно в браузер в качестве ответа. Если вам кажется, что это еще не имеет смысла, это будет недолго, пока вы запустите это приложение.

Чтобы завершить приложение, вам нужно создать сценарий Python на верхнем уровне, определяющий экземпляр приложения Flask. Давайте назовем этот скрипт microblog.py и определим его как одну строку, которая импортирует экземпляр приложения:

from app import app

Помните два объекта app? Здесь вы можете видеть оба вместе в одном предложении. Экземпляр приложения Flask называется app и входит в пакет app. from app import app импортирует переменную app, входящую в пакет app. Если вы считаете это запутанным, вы можете переименовать либо пакет, либо переменную во что то другое.

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

microblog/
  venv/
  app/
    __init__.py
    routes.py
  microblog.py

Верьте или нет, но первая версия приложения завершена! Прежде чем запускать его, Flask нужно сообщить, как его импортировать, установив переменную среды FLASK_APP:

(venv) $ export FLASK_APP=microblog.py

Если вы используете Microsoft Windows, используйте команду ‘set’ вместо ‘export’ в команде выше.

Готовы ли вы быть потрясены? Вы можете запустить свое первое веб-приложение со следующей командой:

(venv) $ flask run
 * Serving Flask app "microblog"
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Прим.переводчика: Я был потрясен поскольку получил ошибку кодировки. Если у вас версия Python старше 3.6 вас скорее всего ждет сюрприз. Типа:

Syntax Error: (unicode error) 'utf-8' codec can't decode byte 0xcf in position 0: invalid continuation byte:

В моем случае виноваты кириллические символы ПК в имени компьютера. Заменил на PK и все заработало. Виноват модуль socket

(venv) C:\microblog>python
Python 3.3.5 (v3.3.5:62cf4e77f785, Mar  9 2014, 10:37:12) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from socket import gethostbyaddr
>>> gethostbyaddr('127.0.0.1')
('Acer-PK', [], ['127.0.0.1'])
>>>

Действительно все заработало:

(venv) C:\microblog>set FLASK_APP=microblog.py

(venv) C:\microblog>flask run
 * Serving Flask app "microblog"
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Что бы написать по русски «Привет, Мир!» потребуется скорректировать

модуль routes.py

Добавить строку # -*- coding: utf-8 -*-

# -*- coding: utf-8 -*-
from app import app

@app.route('/')
@app.route('/index')
def index():
    return "Привет, Мир!"

Когда вы закончите играть с сервером, вы можете просто нажать Ctrl-C, чтобы остановить его.

Поздравляем, вы совершили первый большой шаг, чтобы стать веб-разработчиком!

>>> следующая глава >>>

Проектирование простых приложений в Flask / Хабр

Данная статья, размещенная в репозитории Flask на GitHub, является плодом коллективного творчества небезразличных программистов, а изначальный её автор — Brice Leroy. Она представляет собой достаточно полезный для начинающих материал по Flask. Лично для меня он стал ответом на многие простые вопросы, основным из которых был «как структурировать проект».

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

Описанный пример протестирован на Python 3.5, Flask 0.10, Flask-SQLAlchemy 2.1, Flask-WTF 0.9.

Этот документ не входит в официальную документацию Flask. Он является компиляцией советов, полученных из различных неофициальных источников и никогда не подвергался какой-либо проверке. Описанные методики могут быть весьма полезны, но в то же время и достаточно опасны. Просьба не вносить никаких изменений в оригинальный документ, размещенный на Github, так как на него ссылаются многие ответы на StackOverflow. Вы можете вносить в него любые поправки и заметки, но для размещения используйте личный сайт или блог.

Данная статья является попыткой описать структуру проекта, использующего Flask и базовые модули SQLAlchemy и WTForms.

Установка

Flask

Инструкция по установке Flask.

Я рекомендую использовать virtualenv — эта система очень проста и позволяет размещать несколько виртуальных окружений на одной системе и не требует прав суперпользователя, так как все библиотеки устанавливаются локально.

Flask-SQLAlchemy

SQLAlchemy обеспечивает простой и мощный интерфейс взаимодействия ваших объектов и реляционной базы данных любого типа. Для установки Flask-SQLAlchemy в ваше виртуальное окружение используйте pip:

pip install flask-sqlalchemy

Более полное описание пакета Flask-SQLAlchemy.

Flask-WTF

WTForms упрощает получение данных от пользователя.

pip install Flask-WTF

Более полное описание пакета Flask-WTF.

Введение

Итак, необходимые библиотеки подготовлены. Так должна выглядеть основная структура вашего проекта:

/app/users/__init__.py
/app/users/views.py
/app/users/forms.py
/app/users/constants.py
/app/users/models.py
/app/users/decorators.py

Для каждего модуля (элемента приложения) создаётся следующая структура:

/app/templates/404.html
/app/templates/base.html
/app/templates/users/login.html
/app/templates/users/register.html
...

Шаблоны представления (jinja) хранятся в директории templates и поддиректория модулей:

/app/static/js/main.js
/app/static/css/reset.css
/app/static/img/header.png

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

Для рассматриваемого приложения будут создан один модуль: users. Он обеспечит управление регистрацией и входом пользователей, просмотр данных своего профайла.

Конфигурация

/run.py используется для запуска веб-сервера:

    from app import app
    app.run(debug=True)

/shell.py даст доступ к консоли с возможностью выполнения команд. Возможно, не так удобно, как отладка через pdb, но достаточно полезно (по крайней мере при инициализации базы данных):

    #!/usr/bin/env python
    import os
    import readline
    from pprint import pprint

    from flask import *
    from app import *

    os.environ['PYTHONINSPECT'] = 'True'

Примечание переводчика:

В случае, если вы работаете в ОС Windows (не надо бросать кирпичи!), библиотека readline недоступна. В таком случае необходимо установить в своё виртуальное или реальное окружение python библиотеку pyreadline и обернуть импорт в конструкцию вида:

try:
    import readline
except:
    import pyreadline

В принципе, можно и вовсе обойтись без этой библиотеки, она просто упрощает взаимодействие с консолью, добавляя в нее некоторые bash-like элементы.

/config.py хранит всю конфигурацию приложения. В данном примере в качестве базы данных используется SQLite, так как она очень удобна при разработке. Скорее всего файл /config.py не стоит включать в репозиторий, так как он будет разным на тестовой и промышленной системах.

    import os
    _basedir = os.path.abspath(os.path.dirname(__file__))

    DEBUG = False

    ADMINS = frozenset(['[email protected]'])
    SECRET_KEY = 'This string will be replaced with a proper key in production.'

    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(_basedir, 'app.db')
    DATABASE_CONNECT_OPTIONS = {}

    THREADS_PER_PAGE = 8

    WTF_CSRF_ENABLED = True
    WTF_CSRF_SECRET_KEY = "somethingimpossibletoguess"

    RECAPTCHA_USE_SSL = False
    RECAPTCHA_PUBLIC_KEY = '6LeYIbsSAAAAACRPIllxA7wvXjIE411PfdB2gt2J'
    RECAPTCHA_PRIVATE_KEY = '6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu'
    RECAPTCHA_OPTIONS = {'theme': 'white'}

  • _basedir — переменная, в которую помещается исполняемая директория скрипта;
  • DEBUG определяет появление сообщений об ошибках в тестовом окружении;
  • SECRET_KEY используется для подписи cookies, при его изменении пользователям потребуется логиниться заново;
  • ADMINS содержит адрес электронной почты администраторов для рассылок из приложения;
  • SQLALCHEMY_DATABASE_URI и DATABASE_CONNECT_OPTIONS, как несложно догадаться — опции подключения SQLAlchemy;
  • THREADS_PER_PAGE, как мне кажется, ставил 2 на ядро… Могу ошибаться;
  • WTF_CSRF_ENABLED и WTF_CSRF_SECRET_KEY защищают от подмены POST-сообщений;
  • RECAPTCHA_* используется для входящего в WTForms поля RecaptchaField. Получить приватный и публичный ключи можно на сайте **recaptcha.

Модуль

Настроим модуль users в следующем порядке: определим модели, связанные с моделями константы, далее форму и, наконец, представление и шаблоны.

Модель

/app/users/models.py:

    from app import db
    from app.users import constants as USER

    class User(db.Model):

        __tablename__ = 'users_user'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50), unique=True)
        email = db.Column(db.String(120), unique=True)
        password = db.Column(db.String(120))
        role = db.Column(db.SmallInteger, default=USER.USER)
        status = db.Column(db.SmallInteger, default=USER.NEW)

        def __init__(self, name=None, email=None, password=None):
          self.name = name
          self.email = email
          self.password = password

        def getStatus(self):
          return USER.STATUS[self.status]

        def getRole(self):
          return USER.ROLE[self.role]

        def __repr__(self):
            return '<User %r>' % (self.name)

И её константы в файле /app/users/constants.py:

    # User role
    ADMIN = 0
    STAFF = 1
    USER = 2
    ROLE = {
      ADMIN: 'admin',
      STAFF: 'staff',
      USER: 'user',
    }

    # user status
    INACTIVE = 0
    NEW = 1
    ACTIVE = 2
    STATUS = {
      INACTIVE: 'inactive',
      NEW: 'new',
      ACTIVE: 'active',
    }

К слову о константах: мне нравится, когда константы хранятся в отдельном файле внутри модуля. Константы скорее всего будут использоваться в моделях, формах и представлениях, так что таким образом вы получите удобно организованные данные, которые будет просто найти. К тому же, импортирование констант под именем модуля в верхнем регистре (например USERS для users.constants) поможет избежать конфликтов имен.

Форма

Когда создана модель нужного объекта, необходимо сконструировать форму для работы с ней.

Форма регистрации будет запрашивать имя пользователя, адрес электронной почты и пароль, будут использованы валидаторы для проверки корректности введенных пользователем данных, а поле Recaptcha защитит от регистрации ботов. На случай, если понадобится внедрить пользовательское соглашение, также добавлено поле BooleanField с именем accept_tos. Данное поле помечено, как required, то есть пользователь будет обязан отметить генерируемый формой чекбокс. Форма входа снабжена полями email и password с аналогичными валидаторами.

Описание форм содержится в файле /app/users/forms.py:

    from flask.ext.wtf import Form, RecaptchaField
    from wtforms import TextField, PasswordField, BooleanField
    from wtforms.validators import Required, EqualTo, Email

    class LoginForm(Form):
      email = TextField('Email address', [Required(), Email()])
      password = PasswordField('Password', [Required()])

    class RegisterForm(Form):
      name = TextField('NickName', [Required()])
      email = TextField('Email address', [Required(), Email()])
      password = PasswordField('Password', [Required()])
      confirm = PasswordField('Repeat Password', [
          Required(),
          EqualTo('password', message='Passwords must match')
          ])
      accept_tos = BooleanField('I accept the TOS', [Required()])
      recaptcha = RecaptchaField()

Первый параметр для каждого поля — его метка, например для поля name в форме задана метка NickName. Для полей ввода пароля используется валидатор EqualTo, сравнивающий данные в двух полях.

Более полная информация о возможностях WTForms находится по этой ссылке.

Представление

В представлении объявляется Blueprint — объект схемы модуля, в свойствах которого указывается url_prefix, который будет подставляться в начале любого URLа, указанного в route. Также в представлении используется метод формы form.validate_on_submit, выдающий истину для метода HTTP POST и валидной формы. После успешного входа пользователь перенаправляется на страницу профиля (/users/me). Для предотвращения доступа неавторизованных пользователей создаётся специальный декоратор в файле /app/users/decorators.py:

    from functools import wraps

    from flask import g, flash, redirect, url_for, request

    def requires_login(f):
      @wraps(f)
      def decorated_function(*args, **kwargs):
        if g.user is None:
          flash(u'You need to be signed in for this page.')
          return redirect(url_for('users.login', next=request.path))
        return f(*args, **kwargs)
      return decorated_function

Данный декоратор проверяет наличие данных в переменной g.user. В случае, если переменная не задана, то пользователь не аутенфицирован, тогда задаётся информационное сообщение и осуществляется перенаправление на представление login (вход в систему). Данные в переменную g.user помещаются в функции before_request. Когда вы получаете большой объем данных из профиля пользователя (исторические данные, друзья, сообщения, действия) возможно серьезное замедление работы при обращении к БД, так что кеширование данных пользователей может решить эту проблему (но только пока вы модифицируете объекты централизованно и очищаете кеш при каждом обновлении). Ниже прилагается код представления /app/users/views.py:

    from flask import Blueprint, request, render_template, flash, g, session, redirect, url_for
    from werkzeug import check_password_hash, generate_password_hash

    from app import db
    from app.users.forms import RegisterForm, LoginForm
    from app.users.models import User
    from app.users.decorators import requires_login

    mod = Blueprint('users', __name__, url_prefix='/users')

    @mod.route('/me/')
    @requires_login
    def home():
      return render_template("users/profile.html", user=g.user)

    @mod.before_request
    def before_request():
      """
      pull user's profile from the database before every request are treated
      """
      g.user = None
      if 'user_id' in session:
        g.user = User.query.get(session['user_id'])

    @mod.route('/login/', methods=['GET', 'POST'])
    def login():
      """
      Login form
      """
      form = LoginForm(request.form)
      # make sure data are valid, but doesn't validate password is right
      if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        # we use werzeug to validate user's password
        if user and check_password_hash(user.password, form.password.data):
          # the session can't be modified as it's signed, 
          # it's a safe place to store the user id
          session['user_id'] = user.id
          flash('Welcome %s' % user.name)
          return redirect(url_for('users.home'))
        flash('Wrong email or password', 'error-message')
      return render_template("users/login.html", form=form)

    @mod.route('/register/', methods=['GET', 'POST'])
    def register():
      """
      Registration Form
      """
      form = RegisterForm(request.form)
      if form.validate_on_submit():
        # create an user instance not yet stored in the database
        user = User(name=form.name.data, email=form.email.data, \
          password=generate_password_hash(form.password.data))
        # Insert the record in our database and commit it
        db.session.add(user)
        db.session.commit()

        # Log the user in, as he now has an id
        session['user_id'] = user.id

        # flash will display a message to the user
        flash('Thanks for registering')
        # redirect user to the 'home' method of the user module.
        return redirect(url_for('users.home'))
      return render_template("users/register.html", form=form)

Шаблон

Шаблонизатор Jinja встроен в Flask. Одним из его преимуществ является возможность наследования и встроенной логики (зависимости, циклы, контекстные изменения). Создадим шаблон /app/templates/base.html, от которого будут наследоваться остальные шаблоны. Возможно задание более чем одного наследования (например наследование от шаблона twocolumn.html, который в свою очередь наслудется от main.html). Базовый шаблон также упрощает отображение информационных (flash) сообщений из переменной get_flashed_messages в каждом наследующем шаблоне.

Теперь нет необходимости задавать основную структуру страницы и каждое изменение base.html отразится на наследующих шаблонах. Рекомендуется называть шаблоны в соответствии с вызывающими их представлениями, именно так поименован шаблон /app/templates/users/register.html:

    <html>
      <head>
        <title>{% block title %}My Site{% endblock %}</title>
        {% block css %}
        <link rel="stylesheet" href="/static/css/reset-min.css" />
        <link rel="stylesheet" href="/static/css/main.css" />
        {% endblock %}
        {% block script %}
        <script src="/static/js/main.js" type="text/javascript"></script>
        {% endblock %}
      </head>
      <body>
        <div>{% block header %}{% endblock %}</div>
        <div>
          <div>
            {% for category, msg in get_flashed_messages(with_categories=true) %}
              <p>{{ msg }}</p>
            {% endfor %}
          </div>
        </div>
        <div>{% block content %}{% endblock %}</div>
        <div>{% block footer %}{% endblock %}</div>
      </body>
    </html>

И шаблон /app/templates/users/login.html:

    {% extends "base.html" %}
    {% block content %}
      {% from "forms/macros.html" import render_field %}
      <form method="POST" action=".">
        {{ form.csrf_token }}
        {{ render_field(form.email,) }}
        {{ render_field(form.password,) }}
        <input type="submit" value="Login">
      </form>
      <a href="{{ url_for('users.register') }}">Register</a>
    {% endblock %}

Созданные шаблоны используют макросы для автоматизации создания полей html. Так как этот макрос будет использоваться в различных модулях, он помещен в отдельный файл /app/templates/forms/macros.html:

    {% macro render_field(field) %}
        <div>
        {{ field.label(class="label") }}
        {% if field.errors %}
            {% set css_class = 'has_error ' + kwargs.pop('class', '') %}
            {{ field(class=css_class, **kwargs) }}
            <ul>{% for error in field.errors %}<li>{{ error|e }}</li>{% endfor %}</ul>
        {% else %}
            {{ field(**kwargs) }}
        {% endif %}
        </div>
    {% endmacro %}

Наконец, создан примитивный шаблон /app/templates/users/profile.html:

   {% extends "base.html" %}
   {% block content %}
     Hi {{ user.name }}!
   {% endblock %}

Инициализация приложения

Как несложно догадаться, инициализация приложения происходит в файле /app/init.py:

    import os
    import sys

    from flask import Flask, render_template
    from flask.ext.sqlalchemy import SQLAlchemy

    app = Flask(__name__)
    app.config.from_object('config')

    db = SQLAlchemy(app)

    ########################
    # Configure Secret Key #
    ########################
    def install_secret_key(app, filename='secret_key'):
        """Configure the SECRET_KEY from a file
        in the instance directory.

        If the file does not exist, print instructions
        to create it from a shell with a random key,
        then exit.
        """
        filename = os.path.join(app.instance_path, filename)

        try:
            app.config['SECRET_KEY'] = open(filename, 'rb').read()
        except IOError:
            print('Error: No secret key. Create it with:')
            full_path = os.path.dirname(filename)
            if not os.path.isdir(full_path):
                print('mkdir -p {filename}'.format(filename=full_path))
            print('head -c 24 /dev/urandom > {filename}'.format(filename=filename))
            sys.exit(1)

    if not app.config['DEBUG']:
        install_secret_key(app)

    @app.errorhandler(404)
    def not_found(error):
        return render_template('404.html'), 404

    from app.users.views import mod as usersModule
    app.register_blueprint(usersModule)

    # Later on you'll import the other blueprints the same way:
    #from app.comments.views import mod as commentsModule
    #from app.posts.views import mod as postsModule
    #app.register_blueprint(commentsModule)
    #app.register_blueprint(postsModule)

Экземпляр БД SQLAlchemy и модель Users находятся в двух разных файлах, необходимо импортировать оба из них в общее пространство имен с помощью строки from app.users.views import mod as usersModule. В противном случае команда db.create_all() не принесет результата.

Активируем виртуальное окружение virtualenv и инициализируем БД:

user@Machine:~/Projects/dev$ . env/bin/activate
(env)user@Machine:~/Projects/dev$ python shell.py 
>>> from app import db
>>> db.create_all()
>>> exit()

Теперь можно выполнить команду python run.py и получить сообщение следующего вида:

(env)user@Machine:~/Projects/dev$ python run.py 
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader

Открыв в браузере адрес http://127.0.0.1:500/users/me/ вы будете перенаправлены на страницу входа и увидите ссылку на страницу регистрации.

Введение в фреймворк веб-приложений Flask Python

Если вы разрабатываете веб-приложение на Python, скорее всего, вы используете фреймворк. Фреймворк «представляет собой библиотеку кода, которая упрощает жизнь разработчикам при создании надежных, масштабируемых и обслуживаемых веб-приложений», предоставляя повторно используемый код или расширения для общих операций. Для Python существует ряд фреймворков, включая Flask, Tornado, Pyramid и Django. Новые разработчики Python часто спрашивают: какой фреймворк мне использовать?

Эта серия статей призвана помочь разработчикам ответить на этот вопрос, сравнив эти четыре фреймворка.Чтобы сравнить их функции и операции, я проведу каждого через процесс создания API для простого веб-приложения To-Do List. API сам по себе довольно прост:

  • Новые посетители сайта должны иметь возможность регистрировать новые учетные записи.
  • Зарегистрированные пользователи могут входить в систему, выходить из системы, просматривать информацию в своих профилях и редактировать свою информацию.
  • Зарегистрированные пользователи могут создавать новые элементы задач, просматривать существующие задачи и редактировать существующие.

Все это завершается компактным набором конечных точек API, которые должен реализовывать каждый бэкэнд, вместе с разрешенными методами HTTP:

  • GET /
  • Пост / счета
  • POST / аккаунты / логин
  • GET / аккаунты / выход
  • GET, PUT, DELETE / accounts /
  • GET, POST / accounts / / tasks
  • GET, PUT, DELETE / accounts / / tasks /

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

Запуск и настройка колбы

Как и большинство широко используемых библиотек Python, пакет Flask можно установить из индекса пакетов Python (PPI). Сначала создайте каталог для работы (например, flask_todo — хорошее имя каталога), затем установите пакет flask . Вы также захотите установить flask-sqlalchemy , чтобы ваше приложение Flask имело простой способ взаимодействия с базой данных SQL.

Мне нравится выполнять эту работу в виртуальной среде Python 3. Чтобы попасть туда, введите в командной строке следующее:

 

$ mkdir flask_todo
$ cd flask_todo
$ pipenv install --python 3.6
$ pipenv shell
(flask-someHash) $ pipenv install flask flask-sqlalchemy

Если вы хотите превратить это в репозиторий Git, это хорошее место для запуска git init . Это будет корень проекта, и если вы хотите экспортировать кодовую базу на другой компьютер, наличие здесь всех необходимых установочных файлов поможет.

Хороший способ сдвинуться с мертвой точки — превратить кодовую базу в устанавливаемый дистрибутив Python. В корне проекта создайте setup.py и каталог с именем todo для хранения исходного кода.

setup.py должен выглядеть примерно так:

из настроек импорта setuptools для find_packages 

требуется = [
'flask',
'flask-sqlalchemy',
'psycopg2',
]

setup (
name = 'flask_todo',
version = '0.0 ',
description =' Список дел, созданный с помощью Flask ',
author =' <Ваше настоящее имя здесь> ',
author_email =' <Ваш фактический адрес электронной почты здесь> ',
keywords =' web flask ',
пакетов = find_packages (),
include_package_data = True,
install_requires = требуется
)

Таким образом, всякий раз, когда вы хотите установить или развернуть свой проект, у вас будут все необходимые пакеты в списке требует . У вас также будет все необходимое для настройки и установки пакета в site-packages .Для получения дополнительной информации о том, как написать устанавливаемый дистрибутив Python, ознакомьтесь с документацией на setup.py.

В каталоге todo , содержащем исходный код, создайте файл app.py и пустой файл __init__.py . Файл __init__.py позволяет импортировать из в , как если бы это был установленный пакет. Файл app.py будет корнем приложения. Это то место, где пойдет вся полезность приложения Flask , и вы создадите переменную среды, которая указывает на этот файл.Если вы используете pipenv (как и я), вы можете найти свою виртуальную среду с помощью pipenv --venv и настроить эту переменную среды в сценарии activate вашей среды.

# в вашем скрипте активации, вероятно, внизу (но подойдет где угодно) 

export FLASK_APP = $ VIRTUAL_ENV /../ todo / app.py
export DEBUG = 'True'

При установке Flask вы также установили сценарий командной строки flask .Ввод flask run предложит пакету Flask виртуальной среды запустить HTTP-сервер с использованием объекта app в любом сценарии, на который указывает переменная среды FLASK_APP . Приведенный выше сценарий также включает переменную среды с именем DEBUG , которая будет использоваться немного позже.

Давайте поговорим об этом app объекте.

В todo / app.py вы создадите объект app , который является экземпляром объекта Flask .Он будет действовать как центральный объект конфигурации для всего приложения. Он используется для настройки частей приложения, необходимых для расширенной функциональности, например, для подключения к базе данных и помощи в аутентификации.

Он регулярно используется для настройки маршрутов, которые станут точками взаимодействия приложения. Чтобы объяснить, что это означает, давайте посмотрим на код, которому он соответствует.

from flask import Flask 

app = Flask (__ name__)

@ app.route ('/')
def hello_world ():
"" "Напечатать 'Hello, world!' как тело ответа."" "
return 'Hello, world!'

Это наиболее простое полное приложение Flask. Приложение является экземпляром Flask , принимающим __name__ файла сценария. Это позволяет Python знать, как выполнять импорт из файлов, относящихся к этому. Декоратор app.route украшает первую функцию view ; он может указать один из маршрутов, используемых для доступа к приложению. (Мы рассмотрим это позже.)

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

В приведенном выше примере, когда приложение запущено и доступно по адресу http: // domainname / , пользователь получит «Hello, World!» в качестве ответа.

Подключение базы данных в Flask

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

Flask во многом является веб-фреймворком «сделай сам». Это означает, что нет встроенного взаимодействия с базой данных, но пакет flask-sqlalchemy соединит базу данных SQL с приложением Flask. Пакет flask-sqlalchemy требует только одного для подключения к базе данных SQL: URL-адрес базы данных.

Обратите внимание, что с flask-sqlalchemy можно использовать широкий спектр систем управления базами данных SQL, если в СУБД есть посредник, соответствующий стандарту DBAPI-2.В этом примере я буду использовать PostgreSQL (в основном потому, что я использовал его много), поэтому посредником для общения с базой данных Postgres является пакет psycopg2 . Убедитесь, что в вашей среде установлен psycopg2 , и включите его в список необходимых пакетов в setup.py . Вам не нужно ничего делать с этим; flask-sqlalchemy распознает Postgres по URL-адресу базы данных.

Flask требует, чтобы URL-адрес базы данных был частью его центральной конфигурации через атрибут SQLALCHEMY_DATABASE_URI .Быстрое и грязное решение — жестко закодировать URL-адрес базы данных в приложении.

# top of app.py 
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask (__ name__)
app.config ['SQLALCHEMY_DATABASE_URI'] = 'postgres: // localhost: 5432 / flask_todo'
myb = SQLAlchemy )

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

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

В том же месте, где вы объявили FLASK_APP , объявите DATABASE_URL , указывающую на расположение вашей базы данных Postgres.Разработка обычно работает локально, поэтому просто укажите свою локальную базу данных.

# также в вашем скрипте активации 

export DATABASE_URL = 'postgres: // localhost: 5432 / flask_todo'

Теперь в app.py включите URL-адрес базы данных в конфигурацию вашего приложения.

 

app.config ['SQLALCHEMY_DATABASE_URI'] = os.environ.get ('DATABASE_URL', '')
db = SQLAlchemy (приложение)

И вот так у вашего приложения есть соединение с базой данных!

Определение объектов в Flask

Наличие базы данных для общения — хороший первый шаг.Теперь пора определить некоторые объекты для заполнения этой базы данных.

В разработке приложений «модель» относится к представлению данных некоторого реального или концептуального объекта. Например, если вы создаете приложение для автосалона, вы можете определить модель Car , которая инкапсулирует все атрибуты и поведение автомобиля.

В этом случае вы составляете список дел с задачами, и каждая задача принадлежит пользователю. Прежде чем вы слишком глубоко задумаетесь о том, как они связаны друг с другом, начните с определения объектов для задач и пользователей.

Пакет flask-sqlalchemy использует SQLAlchemy для настройки и информирования структуры базы данных. Вы определите модель, которая будет жить в базе данных, унаследовав от объекта db.Model и определив атрибуты этих моделей как экземпляры db.Column . Для каждого столбца вы должны указать тип данных, поэтому вы передадите этот тип данных в вызов db.Column в качестве первого аргумента.

Поскольку определение модели занимает другое концептуальное пространство, чем конфигурация приложения, создайте модели .py для хранения определений моделей отдельно от app.py . Модель задачи должна иметь следующие атрибуты:

  • id : значение, являющееся уникальным идентификатором для извлечения из базы данных
  • имя : имя или заголовок задачи, которые пользователь увидит, когда задача будет указана в списке
  • примечание : любые дополнительные комментарии, которые человек может захотеть оставить вместе со своей задачей
  • Creation_date : дата и время создания задачи
  • due_date : дата и время, когда задача должна быть завершена (если вообще)
  • выполнено : способ указать, была ли задача завершена

Учитывая этот список атрибутов для объектов Task, объект Task приложения может быть определен следующим образом:

от .app import db 
from datetime import datetime

class Task (db.Model):
"" "Задачи для списка дел." ""
id = db.Column (db.Integer, primary_key = True)
name = db .Column (db.Unicode, nullable = False)
note = db.Column (db.Unicode)
creation_date = db.Column (db.DateTime, nullable = False)
due_date = db.Column (db.DateTime)
завершено = db.Column (db.Boolean, default = False)

def __init __ (self, * args, ** kwargs):
"" "При построении установите дату создания."" "
super () .__ init __ (* args, ** kwargs)
self.creation_date = datetime.now ()

Обратите внимание на расширение метода конструктора класса. В конце концов, любая модель, которую вы создаете, по-прежнему является объектом Python и, следовательно, должна пройти построение для создания экземпляра. Важно убедиться, что дата создания экземпляра модели отражает его фактическую дату создания. Вы можете явно установить это отношение, фактически сказав: «Когда экземпляр этой модели будет построен, запишите дату и время и установите их как дату создания.«

Отношения между моделями

В данном веб-приложении вы можете захотеть выразить отношения между объектами. В примере со списком дел пользователи владеют несколькими задачами, и каждая задача принадлежит только одному пользователю. Это пример отношения «многие-к-одному», также известного как отношение внешнего ключа, где задачи — это «многие», а пользователь, владеющий этими задачами, — «один».

В Flask отношение «многие к одному» можно указать с помощью функции db.relationship .Сначала создайте объект User.

класс User (db.Model): 
"" "Объект User, которому принадлежат задачи." ""
id = db.Column (db.Integer, primary_key = True)
username = db.Column (db.Unicode, nullable = False)
email = db.Column (db.Unicode, nullable = False)
пароль = db.Column (db.Unicode, nullable = False)
date_joined = db.Column (db.DateTime, nullable = False)
token = db.Column (db.Unicode, nullable = False)

def __init __ (self, * args, ** kwargs):
"" "При построении укажите дату создания."" "
super () .__ init __ (* args, ** kwargs)
self.date_joined = datetime.now ()
self.token = secrets.token_urlsafe (64)

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

Теперь, когда модель Пользователь создана, вы можете настроить отношения внешнего ключа.Для «многих» установите поля для user_id User , которому принадлежит эта задача, а также для объекта user с этим идентификатором. Также не забудьте включить аргумент ключевого слова ( back_populate ), который обновляет модель User, когда задача получает пользователя в качестве владельца.

Для «единицы» установите поле для задач , которыми владеет конкретный пользователь. Подобно поддержанию двусторонних отношений в объекте Task, установите аргумент ключевого слова в поле отношения User, чтобы обновить задачу, когда она назначена пользователю.

# на объекте Task 
user_id = db.Column (db.Integer, db.ForeignKey ('user.id'), nullable = False)
user = db.relationship ("user", back_populate = "tasks")

# на объекте User
задач = db.relationship ("Задача", back_populate = "user")

Инициализация базы данных

Теперь, когда модели и отношения моделей установлены, начните настройку базы данных. Flask не имеет собственной утилиты для управления базой данных, поэтому вам придется написать свою собственную (в некоторой степени).Вам не нужно увлекаться этим; вам просто нужно что-то, чтобы распознать, какие таблицы должны быть созданы, и некоторый код для их создания (или отбросить их, если возникнет необходимость). Если вам нужно что-то более сложное, например обработка обновлений таблиц базы данных (то есть миграция базы данных), вам нужно изучить такой инструмент, как Flask-Migrate или Flask-Alembic.

Создайте сценарий с именем initializedb.py рядом с setup.py для управления базой данных. (Конечно, это не нужно называть так, но почему бы не дать имена, соответствующие функции файла?) Внутри initializedb.py , импортируйте объект db из app.py и используйте его для создания или удаления таблиц. initializedb.py должен выглядеть примерно так:

из todo.app import db 
import os

if bool (os.environ.get ('DEBUG', '')):
db.drop_all ()
db.create_all ()

Если установлена ​​переменная среды DEBUG , отбросьте таблицы и перестройте. В противном случае просто создайте таблицы один раз, и все готово.

Просмотры и конфигурация URL

Последние биты, необходимые для подключения всего приложения, — это представления и маршруты.В веб-разработке «представление» (по концепции) — это функциональность, которая запускается при попадании в определенную точку доступа («маршрут») в вашем приложении. Эти точки доступа отображаются как URL-адреса: пути к функциям в приложении, которые возвращают некоторые данные или обрабатывают некоторые данные, которые были предоставлены. Представления будут логическими структурами, которые обрабатывают определенные HTTP-запросы от данного клиента и возвращают некоторый HTTP-ответ этому клиенту.

В Flask представления отображаются как функции; например, см. вид hello_world выше.Для простоты, вот он снова:

 

@ app.route ('/')
def hello_world ():
"" "Распечатать 'Hello, world!' в качестве тела ответа. "" "
return 'Hello, world!'

Когда осуществляется доступ к маршруту http: // domainname / , клиент получает ответ «Hello, world!»

В Flask функция помечается как представление, если она оформлена app.route . В свою очередь, app.route добавляет в центральную конфигурацию приложения карту от указанного маршрута к функции, которая запускается при доступе к этому маршруту.Вы можете использовать это, чтобы приступить к созданию остальной части API.

Начните с представления, которое обрабатывает только запросов GET , и ответьте JSON, представляющим все маршруты, которые будут доступны, и методы, которые можно использовать для доступа к ним.

from flask import jsonify 

@ app.route ('/ api / v1', methods = ["GET"])
def info_view ():
"" "Список маршрутов для этого API." ""
output = {
'info': 'GET / api / v1',
'register': 'POST / api / v1 / accounts',
'single profile detail': 'GET / api / v1 / accounts / ',
' редактировать профиль ':' PUT / api / v1 / accounts / ',
' delete profile ':' DELETE / api / v1 / accounts / ',
' login ':' POST / api / v1 / accounts / login ',
' logout ':' GET / api / v1 / accounts / logout ',
«user tasks»:' GET / api / v1 / accounts / / tasks ',
«create task»: 'POST / api / v1 / accounts / / tasks',
«деталь задачи»: 'GET / api / v1 / accounts / / tasks / ',
«task update»: 'PUT / api / v1 / accounts / / tasks / ',
"delete task":' DELETE / api / v1 / accounts / / tasks / '
}
return jsonify (output )

Поскольку вы хотите, чтобы ваше представление обрабатывало один HTTP-запрос определенного типа , используйте приложение .маршрут , чтобы добавить это ограничение. Аргумент ключевого слова methods принимает список строк в качестве значения, причем каждая строка является типом возможного метода HTTP. На практике вы можете использовать app.route , чтобы ограничить один или несколько типов HTTP-запросов или принять любой, оставив аргумент ключевого слова method в одиночку.

Все, что вы собираетесь вернуть из функции представления , должно быть строкой или объектом, который Flask превращает в строку при построении правильно отформатированного ответа HTTP.Исключениями из этого правила являются случаи, когда вы пытаетесь обрабатывать перенаправления и исключения, создаваемые вашим приложением. Для вас, разработчика, это означает, что вам необходимо уметь инкапсулировать любой ответ, который вы пытаетесь отправить обратно клиенту, в нечто, что можно интерпретировать как строку.

Хорошая структура, которая содержит сложную, но может быть преобразована в строки, — это словарь Python. Поэтому я рекомендую, чтобы всякий раз, когда вы хотите отправить некоторые данные клиенту, вы выбирали Python dict с любыми парами ключ-значение, которые вам нужны для передачи информации.Чтобы превратить этот словарь в правильно отформатированный ответ JSON, заголовки и все остальное, передайте его в качестве аргумента функции Flask jsonify ( from flask import jsonify ).

Приведенная выше функция просмотра берет то, что фактически является списком каждого маршрута, который этот API намеревается обрабатывать, и отправляет его клиенту всякий раз, когда осуществляется доступ к маршруту http: // domainname / api / v1 . Обратите внимание, что Flask сам по себе поддерживает маршрутизацию к точно совпадающим URI, поэтому доступ к тому же маршруту с конечными / приведет к ошибке 404.Если вы хотите обрабатывать и то, и другое с помощью одной и той же функции просмотра, вам понадобятся такие декораторы стека:

 

@ app.route ('/ api / v1', methods = ["GET"])
@ app.route ('/ api / v1 /', methods = ["GET"])
def info_view ():
# бла-бла-бла подробнее код

Интересный случай заключается в том, что если бы определенный маршрут имел завершающую косую черту, а клиент запрашивал маршрут без косой черты, вам не нужно было бы удваивать декораторы. Flask соответствующим образом перенаправит запрос клиента.Странно, что это не работает в обоих направлениях.

Flask запросов и БД

В своей основе задача веб-фреймворка — обрабатывать входящие HTTP-запросы и возвращать HTTP-ответы. Ранее написанное представление на самом деле не имеет ничего общего с HTTP-запросами, за исключением URI, к которому был осуществлен доступ. Он не обрабатывает никаких данных. Давайте посмотрим, как ведет себя Flask, когда данные требуют обработки.

Первое, что нужно знать, это то, что Flask не предоставляет отдельный объект request для каждой функции представления.Он имеет один глобальный объект запроса , который может использовать каждая функция представления, и этот объект удобно называется request и импортируется из пакета Flask.

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

 

@ app.route ('/ a / sample / / route)
def some_view (variable):
# какой-то код бла-бла-бла

Для связи с базой данных в представлении необходимо использовать объект db , который был заполнен в верхней части сценария. Его сеанс атрибут — это ваше соединение с базой данных, когда вы хотите внести изменения.Если вы просто хотите запросить объекты, объекты, построенные из db. Модель , имеют свой собственный уровень взаимодействия с базой данных через атрибут query .

Наконец, любой ответ, который вы хотите получить от представления, более сложного, чем строка, должен быть создан намеренно. Раньше вы создавали ответ, используя словарь «jsonified», но были сделаны определенные предположения (например, код состояния 200, сообщение состояния «ОК», тип содержимого «текст / простой»). Любой особый соус, который вы хотите добавить в свой HTTP-ответ, должен быть добавлен намеренно.

Знание этих фактов о работе с представлениями Flask позволяет вам создать представление, задачей которого является создание новых объектов Task . Давайте посмотрим на код (ниже) и рассмотрим его по частям.

from datetime import datetime 
from flask import request, Response
from flask_sqlalchemy import SQLAlchemy
import json

from .models import Task, User

app = Flask (__ name__)
app.config ['SQLALCHEMY_DATABASE_URI'] = os.environ.get ('DATABASE_URL', '')
db = SQLAlchemy (app)

INCOMING_DATE_FMT = '% d /% m /% Y% H:% M:% S'

@app.route ('/ api / v1 / accounts / / tasks', methods = ['POST'])
def create_task (username):
"" "Создать задачу для одного пользователя." ""
user = User .query.filter_by (username = username) .first ()
if user:
task = Task (
name = request.form ['name'],
note = request.form ['note'],
creation_date = datetime .now (),
due_date = datetime.strptime (due_date, INCOMING_DATE_FMT), если due_date иначе None,
completed = bool (request.form ['завершено']),
user_id = user.id,
)
db.session.add (task)
db.session.commit ()
output = {'msg': 'posted'}
response = Response (
mimetype = "application / json",
response = json.dumps (output),
status = 201
)
return response

Начнем с декоратора @ app.route . Маршрут: '/ api / v1 / accounts / / tasks' , где — переменная маршрута.Поместите угловые скобки в любую часть маршрута, которую вы хотите изменить, затем включите эту часть маршрута в следующую строку в списке параметров с тем же именем . Единственными параметрами, которые должны быть в списке параметров, должны быть переменные в вашем маршруте.

Далее следует запрос:

  пользователь = User.query.filter_by (имя пользователя = имя пользователя) .first ()
  

Чтобы найти одного пользователя по имени, концептуально вам нужно просмотреть все объекты User, хранящиеся в базе данных, и найти пользователей с именем пользователя, совпадающим с запрошенным.С помощью Flask вы можете запросить объект User напрямую через атрибут query для экземпляра, соответствующего вашим критериям. Этот тип запроса предоставит список объектов (даже если это только один объект или ни одного), поэтому для получения желаемого объекта просто вызовите first () .

 

задача = задача (
name = request.form ['name'],
note = request.form ['note'],
creation_date = datetime.now (),
due_date = datetime.strptime (due_date, INCOMING_DATE_FMT), если due_date else Нет,
выполнено = bool (request.форма ['завершена']),
user_id = user.id,
)

Всякий раз, когда данные отправляются в приложение, независимо от используемого метода HTTP, эти данные сохраняются в атрибуте form объекта request . Имя поля во внешнем интерфейсе будет именем ключа, сопоставленного с этими данными в словаре form . Он всегда будет иметь форму строки, поэтому, если вы хотите, чтобы ваши данные были определенного типа, вам придется сделать его явным, приведя его к соответствующему типу.

Еще одна вещь, на которую следует обратить внимание, — это присвоение идентификатора пользователя текущего пользователя вновь созданной задаче Task . Так поддерживается связь по внешнему ключу.

 

db.session.add (задача)
db.session.commit ()

Создание нового экземпляра Task — это замечательно, но его конструкция не имеет внутренней связи с таблицами в базе данных. Чтобы вставить новую строку в соответствующую таблицу SQL, необходимо использовать сеанс , присоединенный к объекту db . db.session.add (task) обрабатывает новый экземпляр Task для добавления в таблицу, но еще не добавляет его. Хотя здесь это делается только один раз, перед фиксацией вы можете добавить столько вещей, сколько захотите. db.session.commit () принимает все поэтапные изменения или «фиксирует» и применяет их к соответствующим таблицам в базе данных.

 

output = {'msg': 'posted'}
response = Response (
mimetype = "application / json",
response = json.дампы (вывод), статус
= 201
)

Ответ является фактическим экземпляром объекта Response с его mimetype , телом и статусом , установленным намеренно. Цель этого представления - предупредить пользователя о том, что он создал что-то новое. Поскольку это представление должно быть частью серверного API, который отправляет и принимает JSON, тело ответа должно быть сериализуемым в формате JSON. Достаточно словаря с простым строковым сообщением. Убедитесь, что он готов к передаче, позвонив по номеру json.выгружает в ваш словарь, что превратит ваш объект Python в действительный JSON. Он используется вместо jsonify , поскольку jsonify создает фактический объект ответа, используя его входные данные в качестве тела ответа. Напротив, json.dumps просто берет заданный объект Python и по возможности преобразует его в допустимую строку JSON.

По умолчанию код состояния любого ответа, отправленного с Flask, будет 200 . Это будет работать в большинстве случаев, когда вы не пытаетесь отправить обратно сообщение определенного уровня перенаправления или уровня ошибки.Так как этот случай явно позволяет интерфейсу узнать, когда был создан новый элемент, установите код статуса 201 , что соответствует созданию нового элемента.

И все! Это базовое представление для создания нового объекта Task во Flask, учитывая текущую настройку приложения To-Do List. Подобные представления могут быть созданы для перечисления, редактирования и удаления задач, но этот пример дает представление о том, как это можно сделать.

Изображение большего размера

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

Узнайте больше о Python на PyCon Cleveland 2018.

.

Мега-учебник Flask, часть I: Hello, World!

Добро пожаловать! Вы собираетесь начать путешествие, чтобы узнать, как создавать веб-приложения с помощью Python и фреймворка Flask. Видео выше даст вам обзор содержания этого руководства. В этой первой главе вы узнаете, как настроить проект Flask. К концу этой главы у вас будет простое веб-приложение Flask, работающее на вашем компьютере!

Для справки, ниже приводится список статей из этой серии.

Примечание 1. Если вы ищете устаревшую версию этого руководства, она здесь.

Примечание 2: Если вы хотите поддержать мою работу над этим блогом или просто не терпите ждать еженедельных статей, я предлагаю полную версию этого руководства в виде электронной книги или набора видео. Для получения дополнительной информации посетите course.miguelgrinberg.com.

Все примеры кода, представленные в этом руководстве, размещены в репозитории GitHub. Загрузка кода с GitHub может сэкономить вам много времени на вводе текста, но я настоятельно рекомендую вам набирать код самостоятельно, по крайней мере, для первых нескольких глав.После того, как вы познакомитесь с Flask и примером приложения, вы сможете получить доступ к коду непосредственно из GitHub, если набор текста станет слишком утомительным.

В начале каждой главы я дам вам три ссылки на GitHub, которые могут быть полезны при работе с главой. Ссылка Обзор откроет репозиторий GitHub для микроблога в том месте, где были добавлены изменения для главы, которую вы читаете, без включения каких-либо изменений, представленных в будущих главах. Zip Ссылка - это ссылка для загрузки zip-файла, включающего все приложение, включая изменения в главе. Ссылка Diff откроет графическое представление всех изменений, которые были сделаны в главе, которую вы собираетесь прочитать.

Ссылки GitHub для этой главы: Browse, Zip, Diff.

Установка Python

Если на вашем компьютере не установлен Python, установите его сейчас. Если ваша операционная система не предоставляет вам пакет Python, вы можете загрузить установщик с официального сайта Python.Если вы используете Microsoft Windows вместе с WSL или Cygwin, обратите внимание, что вы будете использовать не родную для Windows версию Python, а версию, удобную для Unix, которую вам нужно получить из Ubuntu (если вы используете WSL) или из Cygwin.

Чтобы убедиться, что ваша установка Python работает, вы можете открыть окно терминала и ввести python3 или, если это не сработает, просто python . Вот что вам стоит ожидать:

  $ python3
Python 3.5.2 (по умолчанию, 17 ноября 2016 г., 17:05:23)
[GCC 5.4.0 20160609] в Linux
Для получения дополнительной информации введите «помощь», «авторские права», «кредиты» или «лицензия».
>>> _
  

Интерпретатор Python теперь ожидает интерактивного приглашения, в котором вы можете ввести операторы Python. В следующих главах вы узнаете, для чего полезна эта интерактивная подсказка. Но пока вы подтвердили, что Python установлен в вашей системе. Чтобы выйти из интерактивного приглашения, вы можете ввести exit () и нажать Enter. В версиях Python для Linux и Mac OS X вы также можете выйти из интерпретатора, нажав Ctrl-D.В Windows ярлык выхода - Ctrl-Z, за которым следует Enter.

Установка Flask

Следующим шагом является установка Flask, но прежде чем я перейду к этому, я хочу рассказать вам о лучших практиках, связанных с установкой пакетов Python .

В Python пакеты, такие как Flask, доступны в общедоступном репозитории, откуда любой может загрузить и установить их. Официальный репозиторий пакетов Python называется PyPI, что означает индекс пакетов Python (некоторые люди также называют этот репозиторий «магазином сыра»).Установить пакет из PyPI очень просто, потому что Python поставляется с инструментом под названием pip , который выполняет эту работу (в Python 2.7 pip не поставляется вместе с Python и должен устанавливаться отдельно).

Чтобы установить пакет на свой компьютер, используйте pip следующим образом:

  $ pip install <имя-пакета>
  

Интересно, что этот метод установки пакетов в большинстве случаев не работает. Если ваш интерпретатор Python был установлен глобально для всех пользователей вашего компьютера, скорее всего, ваша учетная запись обычного пользователя не будет иметь разрешения на внесение в нее изменений, поэтому единственный способ заставить указанную выше команду работать - запустить ее от администратора. Счет.Но даже без этого осложнения подумайте, что произойдет, когда вы установите пакет, как указано выше. Инструмент pip загрузит пакет из PyPI, а затем добавит его в вашу установку Python. С этого момента каждый скрипт Python, который есть в вашей системе, будет иметь доступ к этому пакету. Представьте себе ситуацию, когда вы завершили работу над веб-приложением, используя Flask версии 0.11, которая на момент запуска была самой последней версией Flask, но теперь ее заменила версия 0.12. Теперь вы хотите запустить второе приложение, для которого вы хотели бы использовать версию 0.12, но если вы замените установленную вами версию 0.11, вы рискуете сломать ваше старое приложение. Ты видишь проблему? Было бы идеально, если бы можно было установить Flask 0.11 для использования в вашем старом приложении, а также установить Flask 0.12 для нового.

Чтобы решить проблему поддержки разных версий пакетов для разных приложений, Python использует концепцию виртуальных сред .Виртуальная среда - это полная копия интерпретатора Python. Когда вы устанавливаете пакеты в виртуальной среде, общесистемный интерпретатор Python не затрагивается, только копия. Таким образом, решение для получения полной свободы установки любых версий ваших пакетов для каждого приложения состоит в использовании отдельной виртуальной среды для каждого приложения. Виртуальные среды имеют дополнительное преимущество: они принадлежат пользователю, который их создает, поэтому им не требуется учетная запись администратора.

Начнем с создания каталога, в котором будет жить проект.Я собираюсь называть этот каталог микроблог , так как это имя приложения:

  $ микроблог mkdir
$ cd микроблог
  

Если вы используете версию Python 3, в нее включена поддержка виртуальной среды, поэтому все, что вам нужно сделать для ее создания, это:

  $ python3 -m venv venv
  

С помощью этой команды я прошу Python запустить пакет venv , который создает виртуальную среду с именем venv .Первое venv в команде - это имя пакета виртуальной среды Python, а второе - имя виртуальной среды, которую я собираюсь использовать для этой конкретной среды. Если вас это сбивает с толку, вы можете заменить второй venv другим именем, которое хотите присвоить своей виртуальной среде. Обычно я создаю свои виртуальные среды с именем venv в каталоге проекта, поэтому всякий раз, когда я загружаю cd в проект, я нахожу соответствующую виртуальную среду.

Обратите внимание, что в некоторых операционных системах вам может потребоваться использовать python вместо python3 в приведенной выше команде. Некоторые установки используют python для выпусков Python 2.x и python3 для выпусков 3.x, в то время как другие сопоставляют python с выпусками 3.x.

После завершения команды у вас будет каталог с именем venv , в котором хранятся файлы виртуальной среды.

Если вы используете любую версию Python старше 3.4 (включая выпуск 2.7) виртуальные среды изначально не поддерживаются. Для этих версий Python вам необходимо загрузить и установить сторонний инструмент под названием virtualenv, прежде чем вы сможете создавать виртуальные среды. После установки virtualenv вы можете создать виртуальную среду с помощью следующей команды:

  $ virtualenv venv
  

Независимо от метода, который вы использовали для его создания, ваша виртуальная среда должна быть создана. Теперь вам нужно сообщить системе, что вы хотите его использовать, и вы делаете это, активируя .Чтобы активировать новую виртуальную среду, используйте следующую команду:

  $ исходный venv / bin / активировать
(venv) $ _
  

Если вы используете окно командной строки Microsoft Windows, команда активации немного отличается:

  $ venv \ Scripts \ активировать
(venv) $ _
  

Когда вы активируете виртуальную среду, конфигурация сеанса терминала изменяется так, что интерпретатор Python, хранящийся внутри него, вызывается при вводе python .Кроме того, приглашение терминала модифицируется и включает имя активированной виртуальной среды. Все изменения, внесенные в ваш сеанс терминала, являются временными и частными для этого сеанса, поэтому они не сохранятся, когда вы закроете окно терминала. Если вы работаете с несколькими открытыми окнами терминала одновременно, вполне нормально активировать в каждом из них разные виртуальные среды.

Теперь, когда у вас создана и активирована виртуальная среда, вы можете, наконец, установить в нее Flask:

  (venv) $ pip install колба
  

Если вы хотите подтвердить, что в вашей виртуальной среде теперь установлен Flask, вы можете запустить интерпретатор Python и импортировать в него Flask:

  >>> импортная колба
>>> _
  

Если этот оператор не выдает ошибок, вы можете поздравить себя, так как Flask установлен и готов к использованию.

Приложение Flask "Hello, World"

Если вы зайдете на веб-сайт Flask, вас встретит очень простой пример приложения, в котором всего пять строк кода. Вместо того чтобы повторять этот тривиальный пример, я собираюсь показать вам более сложный, который даст вам хорошую базовую структуру для написания более крупных приложений.

Приложение будет существовать в пакете . В Python подкаталог, содержащий файл __init__.py , считается пакетом и может быть импортирован.Когда вы импортируете пакет, __init__.py выполняет и определяет, какие символы пакет предоставляет внешнему миру.

Давайте создадим пакет под названием app , в котором будет размещено приложение. Убедитесь, что вы находитесь в каталоге микроблога , а затем выполните следующую команду:

  (venv) приложение $ mkdir
  

__init__.py для пакета app будет содержать следующий код:

приложение / __ init__.py : экземпляр приложения Flask

  из колбы импортной колбы

app = Flask (__ имя__)

из маршрутов импорта приложений
  

Приведенный выше сценарий просто создает объект приложения как экземпляр класса Flask , импортированный из пакета flask. Переменная __name__ , переданная в класс Flask , является предопределенной переменной Python, для которой задано имя модуля, в котором она используется. Flask использует местоположение переданного здесь модуля в качестве отправной точки, когда ему необходимо загрузить связанные ресурсы, такие как файлы шаблонов, о которых я расскажу в главе 2.Для всех практических целей передача __name__ почти всегда приведет к правильной настройке Flask. Затем приложение импортирует модуль routes , который еще не существует.

Один аспект, который поначалу может показаться запутанным, заключается в том, что есть две сущности с именем app . Пакет app определяется каталогом app и сценарием __init__.py и упоминается в заявлении from app import routes .Переменная app определена как экземпляр класса Flask в сценарии __init__.py , что делает его членом пакета app .

Другая особенность заключается в том, что модуль routes импортируется внизу, а не вверху скрипта, как это всегда делается. Нижний импорт - это обходной путь для циклического импорта , распространенной проблемы с приложениями Flask. Вы увидите, что модуль routes должен импортировать переменную app , определенную в этом скрипте, поэтому размещение одного из взаимных импортов внизу позволяет избежать ошибки, которая возникает из-за взаимных ссылок между этими двумя файлами.

Итак, что входит в модуль routes ? Маршруты - это разные URL-адреса, реализуемые приложением. Во Flask обработчики маршрутов приложения записываются как функции Python, называемые функциями просмотра . Функции просмотра сопоставляются с одним или несколькими URL-адресами маршрута, поэтому Flask знает, какую логику выполнять, когда клиент запрашивает данный URL-адрес.

Вот ваша первая функция просмотра, которую вам нужно написать в новом модуле с именем app / routes.py :

приложение / маршруты.py : домашняя страница route

  из приложения для импорта приложений

@ app.route ('/')
@ app.route ('/ индекс')
def index ():
    return "Hello, World!"
  

Эта функция просмотра на самом деле довольно проста, она просто возвращает приветствие в виде строки. Две странные строки @ app.route над функцией - это декораторы , уникальная особенность языка Python. Декоратор изменяет функцию, которая следует за ним. Распространенный паттерн с декораторами - их использование для регистрации функций в качестве обратных вызовов для определенных событий.В этом случае декоратор @ app.route создает связь между URL-адресом, указанным в качестве аргумента, и функцией. В этом примере есть два декоратора, которые связывают URL-адреса / и / index с этой функцией. Это означает, что когда веб-браузер запрашивает любой из этих двух URL-адресов, Flask будет вызывать эту функцию и передавать возвращаемое значение обратно в браузер в качестве ответа. Если это еще не имеет полного смысла, это произойдет через некоторое время, когда вы запустите это приложение.

Для завершения приложения у вас должен быть сценарий Python на верхнем уровне, который определяет экземпляр приложения Flask. Назовем этот сценарий microblog.py и определим его как одну строку, которая импортирует экземпляр приложения:

microblog.py : Основной модуль приложения

  из приложения для импорта приложений
  

Помните две сущности app ? Здесь вы можете увидеть оба вместе в одном предложении. Экземпляр приложения Flask называется app и является членом пакета app .Оператор from app import app импортирует переменную app , которая является членом пакета app . Если вас это сбивает с толку, вы можете переименовать пакет или переменную в другое имя.

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

  микроблог /
  Venv /
  приложение/
    __init__.py
    routes.py
  microblog.py
  

Вы не поверите, но эта первая версия приложения готова! Однако перед запуском Flask нужно указать, как его импортировать, установив переменную среды FLASK_APP :

  (venv) $ export FLASK_APP = микроблог.ру
  

Если вы используете Microsoft Windows, используйте set вместо export в приведенной выше команде.

Готовы ли вы быть потрясенными? Вы можете запустить свое первое веб-приложение с помощью следующей команды:

  (venv) $ пробег
 * Обслуживающее приложение Flask "микроблог"
 * Запуск на http://127.0.0.1:5000/ (нажмите CTRL + C, чтобы выйти)
  

После инициализации сервер будет ждать клиентских подключений. Результат выполнения flask run указывает, что сервер работает на IP-адресе 127.0.0.1, который всегда является адресом вашего компьютера. Этот адрес настолько распространен, что у него также есть более простое имя, которое вы, возможно, видели раньше: localhost . Сетевые серверы прослушивают соединения на определенном номере порта. Приложения, развернутые на производственных веб-серверах, обычно прослушивают порт 443, а иногда и 80, если они не поддерживают шифрование, но для доступа к этим портам требуются права администратора. Поскольку это приложение работает в среде разработки, Flask использует свободно доступный порт 5000.Теперь откройте свой веб-браузер и введите следующий URL-адрес в поле адреса:

  http: // localhost: 5000 /
  

В качестве альтернативы вы можете использовать другой URL:

  http: // localhost: 5000 / индекс
  

Вы видите отображение маршрутов приложения в действии? Первый URL соответствует /, а второй соответствует / index . Оба маршрута связаны с единственной функцией просмотра в приложении, поэтому они производят один и тот же вывод, который представляет собой строку, которую возвращает функция.Если вы введете любой другой URL-адрес, вы получите сообщение об ошибке, так как только эти два URL-адреса распознаются приложением.

Когда вы закончите играть с сервером, вы можете просто нажать Ctrl-C, чтобы остановить его.

Поздравляем, вы сделали первый большой шаг к тому, чтобы стать веб-разработчиком!

Прежде чем закончить эту главу, я хочу упомянуть еще одну вещь. Поскольку переменные среды не запоминаются в сеансах терминала, вам может показаться утомительным всегда устанавливать переменную среды FLASK_APP при открытии нового окна терминала.Начиная с версии 1.0, Flask позволяет вам регистрировать переменные среды, которые вы хотите автоматически импортировать при запуске команды flask . Чтобы использовать эту опцию, вам необходимо установить пакет python-dotenv :

  (venv) $ pip install python-dotenv
  

Затем вы можете просто записать имя и значение переменной среды в файл .flaskenv в каталоге верхнего уровня проекта:

.flaskenv : переменные среды для команды flask

  FLASK_APP = микроблог.ру
  

Это необязательно. Если вы предпочитаете устанавливать переменную среды вручную, это нормально, если вы всегда не забываете это делать.

.

новейших вопросов "колба" - Stack overflow на русском

Переполнение стека

  1. Около
  2. Продукты

  3. Для команд
  1. Переполнение стека
    Общественные вопросы и ответы

  2. Переполнение стека для команд
    Где разработчики и технологи делятся частными знаниями с коллегами

  3. Вакансии
    Программирование и связанные с ним технические возможности карьерного роста

  4. Талант
    Нанимайте технических специалистов и создавайте свой бренд работодателя

  5. Реклама
    Обратитесь к разработчикам и технологам со всего мира

  6. О компании

Загрузка…

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *