diff --git a/flask_applications/NAT.png b/flask_applications/NAT.png new file mode 100644 index 0000000..3a2ce5f Binary files /dev/null and b/flask_applications/NAT.png differ diff --git a/flask_applications/arch.png b/flask_applications/arch.png new file mode 100644 index 0000000..4ccfa22 Binary files /dev/null and b/flask_applications/arch.png differ diff --git a/flask_applications/flask1.ipynb b/flask_applications/flask1.ipynb index 3f89fa7..fa0966c 100644 --- a/flask_applications/flask1.ipynb +++ b/flask_applications/flask1.ipynb @@ -2,9 +2,6 @@ "cells": [ { "cell_type": "markdown", - "metadata": { - "collapsed": true - }, "source": [ "# Пишем сайты на питоне\n", "\n", @@ -28,7 +25,7 @@ "\n", "IP\n", "* *IP-адрес* — (пока что) набор из 4 байт, присваиваемый каждому подключённому к сети устройству\n", - "* Некоторые IP-адреса уникальны, некоторые — нет (внутренние адреса в локальных сетях)\n", + "* Некоторые IP-адреса уникальны, некоторые — нет (внутренние адреса в локальных сетях). Подробнее про [private_network](https://en.wikipedia.org/wiki/Private_network) и про [NAT](https://en.wikipedia.org/wiki/Network_address_translation)\n", "* Практически любой ресурс (например, сайт) можно получить по его IP-адресу (например, через браузер)\n", "* Существуют зарезервированные адреса и диапазоны адресов, например, `127.0.0.1` — адрес данного устройства\n", "\n", @@ -38,6 +35,10 @@ "* Веб-сервер может прослушивать некоторые порты (listen to ports) и по-разному обрабатывать сообщения, поступившие на разные порты\n", "* Если порт не прослушивается, сообщения на этот порт останутся без ответа\n", "\n", + "Сокет(*Socket*) - конечная точка соединения, которая задается парой (`IP:port`)\n", + "\n", + "![NAT](./NAT.png)\n", + "\n", "\n", "__URL__\n", "\n", @@ -62,6 +63,11 @@ "\n", "Написать сайт на питоне значит написать такую программу, которая может работать веб-сервером или использоваться веб-сервером для порождения HTML-кода веб-страниц. Для этого существует несколько модулей, например, Django и Flask\n", "\n", + "\n", + "__Пример архитектуры__\n", + "\n", + "![arch](./arch.png)\n", + "\n", "## flask\n", "\n", "### Intro\n", @@ -93,52 +99,58 @@ "\n", "\n", "#### Пример готового сайта на flask:" - ] + ], + "metadata": { + "collapsed": true + } }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n", - "127.0.0.1 - - [29/May/2018 16:23:17] \"GET / HTTP/1.1\" 200 -\n", - "127.0.0.1 - - [29/May/2018 16:23:17] \"GET /favicon.ico HTTP/1.1\" 404 -\n", - "127.0.0.1 - - [29/May/2018 16:23:17] \"GET /favicon.ico HTTP/1.1\" 404 -\n", - "127.0.0.1 - - [29/May/2018 16:23:17] \"GET / HTTP/1.1\" 200 -\n" - ] - } - ], + "execution_count": 4, "source": [ "from flask import Flask\n", "\n", "app = Flask(__name__)\n", "\n", - "@app.route('/')\n", + "@app.route('/', methods=[\"GET\"])\n", "def index():\n", " return '

Hello, world!

'\n", "\n", "if __name__ == '__main__':\n", " app.run(debug=False)" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " * Serving Flask app '__main__' (lazy loading)\n", + " * Environment: production\n", + "\u001b[31m WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n", + "\u001b[2m Use a production WSGI server instead.\u001b[0m\n", + " * Debug mode: off\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n" + ] + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "Каждая страница сайта порождается какой-то функцией. Декоратор `@app.route(...)` перед функцией показывает, какой адрес будет у страницы, за которую отвечает эта функция:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], "source": [ "@app.route('/')\n", "def index():\n", @@ -147,46 +159,46 @@ "@app.route('/hi')\n", "def hi():\n", " return 'Hi!'" - ] + ], + "outputs": [], + "metadata": { + "collapsed": true + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ "Одна функция может отвечать за несколько разных страниц:\n", "* Во-первых, декораторов может стоять несколько подряд.\n", "* Во-вторых, декораторы могут содержать переменные.\n", "\n", "Пример:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], "source": [ "@app.route('/user/')\n", "def user_index(user):\n", " return 'This is the page of' + user" - ] + ], + "outputs": [], + "metadata": { + "collapsed": true + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ "Переменные в адресах могут быть разного типа: `int` — целое число, `float` — действительное число, `path` — строка, которая может содержать слэши. Тип переменной можно указать вот так:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], "source": [ "import datetime\n", "\n", @@ -195,11 +207,14 @@ " h = datetime.datetime.today().hour\n", " h += shift\n", " return 'Time in your country:' + str(h)" - ] + ], + "outputs": [], + "metadata": { + "collapsed": true + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## Перенаправление\n", "\n", @@ -207,13 +222,12 @@ "\n", "- если пользователь заходит на страницу /time в рабочее время (с 10 до 18), то он перенаправляется на главную страницу сайта,\n", "- если пользователь заходит на страницу в другое время, то он перенаправляется на страницу /hi." - ] + ], + "metadata": {} }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 3, "source": [ "import datetime\n", "\n", @@ -240,17 +254,37 @@ "def time_redirect():\n", " h = datetime.datetime.today().hour\n", " if 10 < h < 18:\n", - " return redirect(url_for('index'))\n", + " return redirect(\"/\")\n", " return redirect(url_for('hi'))\n", "\n", "\n", "if __name__ == '__main__':\n", - " app.run(debug=True)" - ] + " app.run(debug=False)" + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " * Serving Flask app '__main__' (lazy loading)\n", + " * Environment: production\n", + "\u001b[31m WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n", + "\u001b[2m Use a production WSGI server instead.\u001b[0m\n", + " * Debug mode: off\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n" + ] + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "\n", "### Шаблоны\n", @@ -262,26 +296,26 @@ "Эти специальные фрагменты пишутся внутри `{% ... %}` или `{{ ... }}`. При порождении HTML эти фрагменты заменяются на какой-то HTML-код по определённым правилам.\n", "\n", "Чтобы породить HTML по шаблону, используется функция `render_template()`:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], "source": [ "from flask import render_template\n", "@app.route('/hello/')\n", "@app.route('/hello/')\n", "def hello(name=None):\n", " return render_template('hello.html', name=name)" - ] + ], + "outputs": [], + "metadata": { + "collapsed": true + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ "* Функция `render_template` заменяет все вставки в фигурных скобках на какой-то HTML.\n", "* Во вставках можно использовать переменные, которые передаются в шаблон через `render_template`.\n", @@ -315,37 +349,36 @@ "`{% elif ... %}`\n", "\n", "`{% else %}`\n" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], "source": [ "{% if username|length > 20 %}\n", "

Слишком длинное имя!

\n", "{% else %}\n", "

{{ username }}

\n", "{% endif %}" - ] + ], + "outputs": [], + "metadata": { + "collapsed": true + } }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## Словари в шаблонах\n", "\n", "Предположим, у нас есть словарь, в котором хранятся имена наших друзей и их почтовые адреса. И мы хотим выводить эти имена с адресами на нашем сайте. Мы можем написать что-то такое:\n" - ] + ], + "metadata": {} }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 3, "source": [ "from flask import Flask\n", "from flask import render_template\n", @@ -362,20 +395,41 @@ "\n", "if __name__ == '__main__':\n", " app.run()" - ] + ], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " * Serving Flask app '__main__' (lazy loading)\n", + " * Environment: production\n", + "\u001b[31m WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n", + "\u001b[2m Use a production WSGI server instead.\u001b[0m\n", + " * Debug mode: off\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + " * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n", + "127.0.0.1 - - [19/Nov/2021 09:09:01] \"GET / HTTP/1.1\" 200 -\n", + "127.0.0.1 - - [19/Nov/2021 09:09:01] \"\u001b[33mGET /favicon.ico HTTP/1.1\u001b[0m\" 404 -\n" + ] + } + ], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "Тогда в папке `templates` нам нужно создать файл `index.html`, в котором будут перебираться элементы словаря. Делается это с помощью функции `items()`. Вот так будет выглядеть `index.html`:" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ "\n", "\n", @@ -392,22 +446,22 @@ "\n", "\n", "" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "Когда вы пишете сайт на фласке у себя на компьютере, можно написать вместо `app.run()` вот так: `app.run(debug=True)`. Это значит, что если на сайте возникнет ошибка, то на странице с ошибкой выведется ее описание, и вы легко сможете понять, в каком месте кода все падает. Но когда вы будете выкладывать сайт в Интернет, нужно убедиться, что `debug` отключен.\n", "\n", "## Как вывести на веб-страничку содержимое текстового файла?" - ] + ], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ "from flask import Flask\n", "from flask import url_for, render_template, request, redirect\n", @@ -422,13 +476,13 @@ "\n", "if __name__ == '__main__':\n", " app.run(debug=True)" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ "\n", "\n", @@ -445,11 +499,12 @@ "

\n", "\n", "" - ] + ], + "outputs": [], + "metadata": {} }, { "cell_type": "markdown", - "metadata": {}, "source": [ "#### Задание\n", "\n", @@ -458,14 +513,14 @@ "+ на главной странице будет выводиться Ваше любимое стихотворение\n", "+ с главной страницы можно перейти на страницы stats и thanks\n", "+ на странице stats выведен частотный словарь стихотворения и соответствующий график" - ] + ], + "metadata": {} } ], "metadata": { "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" + "name": "python3", + "display_name": "Python 3.9.7 64-bit ('venv': venv)" }, "language_info": { "codemirror_mode": { @@ -477,9 +532,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.5" + "version": "3.9.7" + }, + "interpreter": { + "hash": "2ce43fa76ab3efd8b793de81ff92f0816c1b946b31e6af34d67351b015f361e9" } }, "nbformat": 4, "nbformat_minor": 1 -} +} \ No newline at end of file