VueJS конфликтует с Jinja2 и Django template

vuejs logo jinja2 logo django logo

В приложениях VueJS используется {{ varname }} для обработки шаблонов. В Jinja2 и Django шаблонах при рендеринге шаблона также используются фигурные скобки. Из-за этого возникает конфликт. Есть 3 способа решения проблемы.

VueJS — заменить фигурные скобки на что то другое

<!-- js файл -->
new Vue({
  delimiters: ['{*', '*}'],
  data: {
    VueVAR: 'test'
  }
})
<!-- html файл -->
<div id="app">
  {* VueVAR *} <!-- vuejs -->
  {{ name }}  <!-- переменная в Jinja2 или Django шаблоне переданная из views.py -->
</dev>

Использовать RAW в html для Jinja2

<!-- js файл -->
new Vue({
  data: {
    VueVAR: 'test'
  }
})
<!-- html файл -->
<div id="app">
  {{ VueVAR }}  <!-- vuejs -->
  {% raw %}
     {{ name }}  <!-- переменная в Jinja2 из views.py -->
  {% raw %}
</dev>

Для Django templates поменять фигурные скобки

# в файле setting.py
VARIABLE_TAG_START = '{*'
VARIABLE_TAG_END = '*}'
<!-- js файл -->
new Vue({
  data: {
    VueVAR: 'test'
  }
})
<!-- html файл -->
<div id="app">
{{ VueVAR }} <!-- vuejs -->
{* name *} <!-- переменная в Django template из views.py -->
</dev>

В своих проектах я всегда использую первый способ.

Посредник — посредственный

Это пост не про программирования. А про посредственных посредников.

Переезд №1

Ситуация дума всем очевидно, куда не обратись, везде агрегаторы и посредники.

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

Приехал водитель на 10 минут раньше времени, а грузчиков нет. Я спрашиваю где они? Водитель пояснил, что грузчики это отдельная организация, и они добираются своим ходом сами.

Грузчик приехал один вовремя, вполне адекватный человек, мужчина лет 40-45, одет по форме, комбинезон, удобная обувь, второй опоздал, мужчина лет 50 в резиновых сапогах, видно, что всю жизнь пьёт.

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

Долго, дорого и не качественно.

Переезд №2

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

Позвонил оператору одной из фирм, сразу сказал, что если грузчики будут «алкоголиками», отменю заказ, мне нужны настоящая команда!

Уточнил у оператора насчёт машины, и заказал на 100 рублей дороже в час, за то большего объёма. (Легче и быстрей загружать).

Машина приехала на 20 минут

Грузчики пришли на 10 минут раньше, спросили меня где можно переодеться, одели спец одежду, удобную обувь, 2 молодых человека лет 25-30, спортивного телосложения.

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

Переезд планировал заранее, выбрал выходной день, что бы не стоять в пробках.

Зная, что машина и грузчики оплачиваются отдельная, машину удалось отпустить раньше (с начало выгрузили всё на улицу, потом заносили домой). 

Выводы

Тогда я не понял, в чём дело. Сильно мой разум был затуманен, теперь мне очевидно, есть 2 правила которые сэкономят силы, нервы, время и деньги:

  1. Свои действия — планируй и действую от плана.
  2. Уточняй все важные детали, и договаривайся сразу о увольнении при несоблюдение договорённостей.

В Vue-awesome-swiper не работают стрелки в слайдере

Столкнулся при использовании vue awesome swiper с неработающими стрелками в слайдере и пагинатором.

Оказалось проблема в версии новая версия swiper 6.1.1 не совместима с текущей версией плагина vue-awesome-swiper 4.1.1.

Делал как в документации, но только параметр loop подхватывался, остальные игнорировались:

        data: {
            swiperOption: {
                navigation: {
                    nextEl: '.swiper-button-next',
                    prevEl: '.swiper-button-prev'
                },
                loop: true,
                autoplay: {
                    delay: 3000,
                    stopOnLastSlide: false,
                },
            }
        }

Откатился на версию «swiper»: «^5.4.5» всё заработало.

Vim и Git показывать измененные строки

Очень удобно при работе с файлом видеть, какие строки были изменены но ещё не добавлены в Git.

Для этого прекрасно подходит плагин tpope/vim-fugitive.

Ставлю его через Vundle добавив в .vimrc строчку:

Plugin 'tpope/vim-fugitive'

Установка:

# перечитать файл
:source ~/.vim/vimrc
# установить плагин
:VundleInstall

Python3 установка pip пакетов offline

Бывает необходимо установить пакеты для python на машине без интернета. Способов много, я выбрал для себя один, его и использую. «Легко» и «просто» можно скачать необходимые пакеты вместе с зависимостями и установить на другой машине, если сделать следующие.

На машине с интернетом

python3 -m venv vevn
source venv/bin/active
pip install pip --upgrade
# директория для скачивания пакетов
mkdir pkg
cd pkg
# отдельно скачиваю последнею версию pip
pip download pip
# скачиваю необходимые пакеты с зависимостями
pip download -r ../requirements.txt

На машине без интернета

python3 -m venv vevn
source venv/bin/active
# устанавливаю ранее скаченный pip (версия может быть другая)
pip install pkg/pip-20.1-py2.py3-none-any.whl
# установка пакетов из списка requirements.txt, пакеты должны лежать в pkg (директория)
pip install --no-index --find-links pkg -r requirements.txt

Результат выполнения

# вывод консоли у меня
pip install --no-index --find-links pkg -r requirements.txt 
Looking in links: pkg
Processing ./pkg/Flask-1.1.2-py2.py3-none-any.whl
Processing ./pkg/Flask_WTF-0.14.3-py2.py3-none-any.whl
Processing ./pkg/et_xmlfile-1.0.1.tar.gz
Processing ./pkg/openpyxl-3.0.3.tar.gz
Processing ./pkg/jdcal-1.4.1-py2.py3-none-any.whl
Processing ./pkg/pylint-2.5.2-py3-none-any.whl
Processing ./pkg/itsdangerous-1.1.0-py2.py3-none-any.whl
Processing ./pkg/Jinja2-2.11.2-py2.py3-none-any.whl
Processing ./pkg/Werkzeug-1.0.1-py2.py3-none-any.whl
Processing ./pkg/click-7.1.2-py2.py3-none-any.whl
Processing ./pkg/WTForms-2.3.1-py2.py3-none-any.whl
Processing ./pkg/mccabe-0.6.1-py2.py3-none-any.whl
Processing ./pkg/isort-4.3.21-py2.py3-none-any.whl
Processing ./pkg/toml-0.10.1-py2.py3-none-any.whl
Processing ./pkg/astroid-2.4.1-py3-none-any.whl
Processing ./pkg/MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl
Processing ./pkg/typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl
Processing ./pkg/wrapt-1.12.1.tar.gz
Processing ./pkg/lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl
Processing ./pkg/six-1.14.0-py2.py3-none-any.whl
Could not build wheels for et-xmlfile, since package 'wheel' is not installed.
Could not build wheels for openpyxl, since package 'wheel' is not installed.
Could not build wheels for wrapt, since package 'wheel' is not installed.
Installing collected packages: itsdangerous, MarkupSafe, Jinja2, Werkzeug, click, Flask, WTForms, Flask-WTF, et-xmlfile, jdcal, openpyxl, mccabe, isort, toml, typed-ast, wrapt, lazy-object-proxy, six, astroid, pylint
    Running setup.py install for et-xmlfile ... done
    Running setup.py install for openpyxl ... done
    Running setup.py install for wrapt ... done
Successfully installed Flask-1.1.2 Flask-WTF-0.14.3 Jinja2-2.11.2 MarkupSafe-1.1.1 WTForms-2.3.1 Werkzeug-1.0.1 astroid-2.4.1 click-7.1.2 et-xmlfile-1.0.1 isort-4.3.21 itsdangerous-1.1.0 jdcal-1.4.1 lazy-object-proxy-1.4.3 mccabe-0.6.1 openpyxl-3.0.3 pylint-2.5.2 six-1.14.0 toml-0.10.1 typed-ast-1.4.1 wrapt-1.12.1

Мой файл requirements.txt для примера

Flask==1.1.2
Flask-WTF==0.14.3
et-xmlfile==1.0.1
openpyxl==3.0.3
jdcal==1.4.1
pylint==2.5.2

Установка из tar.gz или whl

# установка одного пакета из архива
pip install ./pkg-name.tar.gz

Python3 и MySQL что установить?

Для работы нужна библиотека mysqlclient. Установка библиотеки mysqlclient для работы с MySQL и Python3 происходит следующим образом (в Debian 9)

sudo apt install python3-dev libsqlclient-dev default-libmysqlclient-dev
python3 -m venv venv
source venv/bin/activate
pip install mysqlclient

В Debian 10 buster и Python3.7 с MySQL (MariaDB)

Я использую библиотеку PyMySQL. Если в проекте используется SQLAlchemy то в SQLALCHEMY_DATABASE_URI mysql://… нужно поменять на mysql+pymysql://…

pip install PyMySQL

Для Python2 использовать старый модуль MySQL-python.

AJAX и jQuery — Flask (1.1.x) простой пример

пример работы ajax с Flask
Пример работы AJAX с Flask

Flask не стоит на месте. Решил дополнить пример обработки формы  при помощи AJXA. Я использую данный код для обработки формы заказа звонка на сайтах. Приведу список requirements.txt (для гарантии работы кода лучше использовать его). Версия Python 3.8.2.

Установка Flask и библиотек

#  настройка виртуального окружения python, всё как всегда :)
python3 -m venv venv
#  активация окружения
source venv/bin/activate
#  обновления pip
pip install pip --upgrade
#  установка всего необходимого
pip install -r requirements.txt
Flask==1.1.2
Flask-WTF==0.14.3

Подготовка

Необходимо создать структуру проекта, лучше сделать для примера как я привел ниже:

#  структура проекта
.
├── app.py
├── forms.py
├── requirements.txt
└── templates
    ├── base.html
    └── index.html

Создать директорию templates, и два файла в ней base.html и index.html.

mkdir templates
touch templates/base.html
touch templates/index.html

Содержимое файла base.html, всё как обычно, стоить отметить в строке 6 подключение библиотеки jQuery чере cnd google.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask AJAX + jQuery simple - {{ title }}</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
    {% block content %}
    {% endblock content %}
    <div id="msg"></div>
</body>
</html>

Так же создаю файл с index.html который расширяет base.html.

Строки 3-8 содержат форму.

Строка 10 содержит div с id=»msg» в него будет записан ответ с сервера.

Сроки 13-18 код который связывает события «submit» кнопки из формы, с функцией отправки данных через ajax, в качестве параметра передается id формы и id элемента для записи ответа (без #). В данном случаи «form1» и «msg». event.preventDefault() — отменяет стандартное поведение. 

Строки 23-45 функция sendAjaxForm отправляет данные формы (form1).

 

{% extends "base.html" %}
{% block content %}
    <form action="/send" id="form1" method="post">
        {{ form.csrf_token }}
        {{ form.name.label }} {{ form.name() }}
        {{ form.phone.label }} {{ form.phone() }}

        <input type="submit" value="Отправить"/>
    </form>
    <div id="msg"></div>
    <script>
        /* переопределить поведение кнопки "Отправить" */
        $(document).ready(function () {
            $("#form1" ).submit(function( event ) {
              sendAjaxForm("form1", "msg");
              event.preventDefault();
            });
        });


        /* отправка формы через ajax */
        function sendAjaxForm(form_ajax, msg) {
            var form = $("#" + form_ajax);
            $.ajax({
                type: form.attr('method'),
                url: form.attr('action'),
                data: form.serialize(),
                success: function (response) {
                    var json = jQuery.parseJSON(response);
                    $('#' + msg).html(json.msg);
                    if (json.success == 'true') {
                        form.trigger('reset');
                    }
                    else
                    {
                        alert("Что-то пошло не так!");
                        console.log("Ошибка");
                    }
                },
                error: function (error) {
                    console.log(error);
                }
            });
        }
    </script>
{% endblock %}

Подробней про функцию sendAjaxForm.

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

Итак, строка 23 просто получаем объект формы по id (#frim1).

Строка 25 type должен быть GET или POST это метод, беру его из параметров формы (method).

Аналогична строка 26 url должен содержать адрес для обработки запроса, в данном случаи так же берётся из формы (action). (её обрабатывает на сервере функция send см. файл app.py строка 22).

Строка 27 данные формы готовятся к отправки на сервер.

Строки 28 если всё прошло успешно, получен ответ от сервера он будет в response.

Строка 29 преобразую данные в объект json для удобства работы.

Строка 30 вывожу ответ в div с id=msg.

Строки 31-33 — успех, очищаю форму.

Строки 34-38 — что то не так, ошибка.

Строки 40-42 — если ошибки в запросе на сервер, нет связи, ошибка в url и т. д.

С HTML и JavaScript всё 🙂

Форма Flask файл forms.py

Строки 8-9 параметр DataRequired говорит о том, что они обязательны для заполнения. Length — размер не меньше 4 знаков.

В старых версиях wtf вместо StringField был TextField, сейчас лучше писать StringField. В версии 3.0 TextField перестанет работать.

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
from wtforms.validators import Length


class ContactForm(FlaskForm):
    name = StringField('Имя', validators=[DataRequired()])
    phone = StringField('Телефон', validators=[DataRequired(), Length(min=4)])

Файл app.py сам проект на Flask

Строка 6 форма обратной связи.

Строка 21 декоратор обработки url «/send».

Строка 22 функция отправки «сообщения».

Строка 24 если валидация успешна, возвращает json с положительным ответом (строка 27) иначе с отрицательным (строка 30).

from flask import Flask
from flask import request
from flask import render_template
import json
#  форма для обратной сзвязи
from forms import ContactForm

app = Flask(__name__)
app.config['SECRET_KEY'] = "12345"


@app.route('/', methods=['GET', 'POST'])
def index():
    form = ContactForm()

    return render_template("index.html",
                           title="index page",
                           form=form)


@app.route('/send', methods=['POST'])
def send():
    form = ContactForm()
    if request.method == "POST":
        if form.validate_on_submit():
            #  отправить почту, записать в БД и т. д.
            return json.dumps({'success': 'true', 'msg': 'Ждите звонка!'})
        else:
            #  обработать ошибку
            return json.dumps({'success': 'false', 'msg': 'Ошибка на сервере!'})


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

Запуск app.py

python3 app.py 
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 334-159-801

Результат работы

Простое приложение Flask + AJAX + jQuery
Результат работы
Ввод данных  Flask + AJAX + jQuery
Ввод данных
Данные успешно отправлены
Данные успешно отправлены
Пример ошибки

Видео с примером работы Flask + jQuery + AJAX.

Исходники

Готовый пример можно скачать с github

git clone https://github.com/newivan/simply-ajax

Flask настройка reCAPTCHA от Google

Вездесущий спам — читал где то, что одно время 80% почтового трафика это был SPAM.

Сейчас уже почтового спама не так много доходит до нас (просто средства борьбы с ним стали лучше).

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

С годами, образовалось большое количество сайтов, и клиенты стали жаловаться на спам, конечно при разработке были сделаны простые защиты (скрытое поле и/или 2+2 и т. д. и т. п.) так же был опыт использования reCAPTCHA v2 — но были свои нюансы.

reCAPTCHA v2 считаю, что это хорошее решение. Да и ещё оно работает из коробки с flask-wtf примерно с 2017 года. Раньше нужно было «колхозить».

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

Что понадобиться?

  1. Ключи от google публичный и приватный. (Я создал для хоста 127.0.0.1 возможно для теста подойдут они. А так нужно при создании указывать домен на котором будет сайт с капчей.)
  2. Flask и flask-wtf.

Структура проекта

.
├── app.py
├── forms.py
├── requirements.txt
└── templates
    ├── base.html
    └── index.html

Пошаговые действия

Создать виртуальное окружение для python, всё как обычно:

python3.7 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Содержимое requirements.txt

Flask==1.1.2
Flask-WTF==0.14.3

Создаю директорию для шаблонов:

mkdir templates

Создаю файл base.html (в директории templates) следующего вида, строки 8,9 содержат блок который будет расширен содержимым файла index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask RecaptchaField simple - {{ title }}</title>
</head>
<body>
{% block content %}
{% endblock content %}
</body>
</html>

Содержимое файла index.html (в директории templates). Строка 1 указывает какой шаблон будет расширен текущим. Строка 5 будет содержать сообщение об успехе или провале валидации. Собственно в 11 строке содержится recaptcha.

{% extends "base.html" %}
{% block content %}

    {% if msg %}
	Результат: {{ msg }}	
    {% endif %}
    
    <form action="/" method="post">
        {{ form.csrf_token }}	
        {{ form.text.label }} {{ form.text(size=20) }}
        {{ form.recaptcha }}
        <input type="submit" value="Отправить">
    </form>

{% endblock %}

Следующий файл forms.py (корень проекта). Строка 8 содержит поле комментарий DataRequired обозначает обязательно для заполнения. Строка 9 recaptcha поле с «галочкой».

from flask_wtf import FlaskForm
from flask_wtf import RecaptchaField
from wtforms import TextField
from wtforms.validators import DataRequired


class ContactForm(FlaskForm):
    text = TextField('Комментарий', validators=[DataRequired()])
    recaptcha = RecaptchaField()

И наконец самый главный файл приложения app.py (корень проекта).

Строка 5 — ранее описанная форма.

Строка 10, 11 — ключи которые нужно получить в google используя аккаунт google.

Строка 16 — форма для передачи в шаблон и проверки валидности.

Строка 18 — если метод POST значит была нажата в форме кнопка submit и соответственно нужно проверить полученные данные на валидность.

Строка 19 — проверка данных на валидность.

Если валидация пройдена, то msg примет значение «Успех!» иначе «Ошибка валидации».

from flask import Flask
from flask import request
from flask import render_template
#  форма с валидацией и капчей
from forms import ContactForm
app = Flask(__name__)
app.config['SECRET_KEY'] = "12345"

#  ключи recaptcha от google
app.config['RECAPTCHA_PUBLIC_KEY'] = "6Ld74-oUAAAAAJC0UOY6PtrOrNcxQ2VQCfGAqBOC"
app.config['RECAPTCHA_PRIVATE_KEY'] = "6Ld74-oUAAAAAD2_Jl2IVKh2uCCI9OPX_7oTdLz4"


@app.route('/', methods=['GET', 'POST'])
def index():
    form = ContactForm()
    msg = ""
    if request.method == "POST":
        if form.validate_on_submit():
            msg="Успех!"
            #  отправить почту, записать в БД
        else:
            msg="Ошибка валидации"
            #  обработать ошибку

    return render_template("index.html",
                           title="index page",
                           form=form,
                           msg=msg)


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

Запуск проекта:

python3 app.py
Заполнили комментарий и нажали на галочку
Успешная валидация
Ошибка валидации
Пример работы reCAPTCHA с Flask

В видео видно, что если ошибиться несколько раз, будет показана капча и просто «галочкой» уже не отделаться.

В заключении

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

В новой версии flask-wtf появиться параметр RECAPTCHA_DISABLE  который позволит красиво отключать и включать проверку капчи.

А как быть, если нужно отключить проверку  капчи сейчас?

Вообще это одна из проблем, почему мне не нравилось использовал данную капчу, решение пока у меня такое, создавать две одинаковые формы с reCAPTCHA и без. Пример кода ниже forms.py и app.py.  Выделил строки которые поменялись.

Файл forms.py

from flask_wtf import FlaskForm
from flask_wtf import RecaptchaField
from wtforms import TextField
from wtforms.validators import DataRequired

class ContactForm(FlaskForm):
    text = TextField('Комментарий', validators=[DataRequired()])

class ContactRecaptchaForm(ContactForm):
    recaptcha = RecaptchaField()

Файл app.py

from flask import Flask
from flask import request
from flask import render_template
app = Flask(__name__)
app.config['SECRET_KEY'] = "12345"

#  ключи recaptcha от google
app.config['RECAPTCHA_PUBLIC_KEY'] = "6Ld74-oUAAAAAJC0UOY6PtrOrNcxQ2VQCfGAqBOC"
app.config['RECAPTCHA_PRIVATE_KEY'] = "6Ld74-oUAAAAAD2_Jl2IVKh2uCCI9OPX_7oTdLz4"
app.config['RECAPTCHA_DISABLE'] = True #  будет капча или нет

#  форма с валидацией и капчей или без неё.
#  в новой версии flask-wtf планируется сделать RECAPTCHA_DISABLE красиво
#  из коробки, это временное решение
if app.config['RECAPTCHA_DISABLE'] == True:
    from forms import ContactRecaptchaForm as ContactForm
else:
    from forms import ContactForm


@app.route('/', methods=['GET', 'POST'])
def index():
    form = ContactForm()
    msg = ""
    if request.method == "POST":
        if form.validate_on_submit():
            msg="Успех!"
            #  отправить почту, записать в БД
        else:
            msg="Ошибка валидации"
            #  обработать ошибку

    return render_template("index.html",
                           title="index page",
                           form=form,
                           msg=msg)


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

Готовый код с примером Flask + reCAPTCHA v2 Google

Можно скачать его тут.

git clone https://github.com/newivan/flask-simple-captcha

SQLite3 создать dump базы данных и восстановить из него

Бывает необходимость, поработать с текстом в базе SQLite. Для этого я выгружаю в sql все таблицы с данными, провожу манипуляцию и заливаю обратно.

Ниже представлены команды для работы с дампом базы данных, создание и восстановление.

 

Создание и восстановление из дампа БД SQLite

Создать dump:

sqlite3 bd.sqlite .dump > dump.sql

Восстановить из dump:

sqlite3 new-bd.db < dump.sql

Работа с одной таблицей

Можно создать только dump определенной таблицы, в данном случаи user:

sqlite new-bd.db
sqlite> .output user.sql
sqlite> .dump user
sqlite> .exit

Отредактировать файл как нужно и залить таблицу обратно, удалив её перед этим из базы:

Удалить таблицу:

#  работа с базой
sqlite new-bd.db 
#  список таблиц
sqlite> .tables
DROP TABLE user;
sqlite> .exit

Восстановить одну таблицу:

sqlite3 new-bd.db < user.sql

Книга: Стандартная библиотека Python3 Справочник с примерами — Даг Хеллман 2-е издание

Книга: Стандартная библиотека Python 3 Справочник с примерами
Книга: Справочник с примерами.
Даг Хеллман «Стандартная библиотека Python 3» Диалектика, 2019 год, 1375 стр., 2-е издание

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

Книга огромная, читать (смотреть её) удобно только за столом.

Стандаартная библиотека Python3 Даг Хеллман

Описывает относительно современную версию языка Python3.6 и 3.7. Материал из книги будет актуален ещё несколько лет. Если 2.7 версию использовали столько лет (и будет ещё тянуть старые проекты) то приобретение данный книги, если вы в профессии оправданно.

Оглавление

Глава 1. Текст
Глава 2. Структуры данных
Глава 3. Алгоритмы
Глава 4. Дата и время
Глава 5. Математика
Глава 6. Файловая система
Глава 7. Постоянное хранение и обмен данными
Глава 8. Сжатие и архивирование данных
Глава 9. Криптография
Глава 10. Параллельные вычисления: процессы, потоки и сопрограммы
Глава 11. Обмен данными по сети
Глава 12. Интернет
Глава 13. Электронная почта
Глава 14. Строительные блоки приложений
Глава 15. Интернационализация и локализация приложений
Глава 16. Инструменты разработки
Глава 17. Инструменты среды времени выполнения
Глава 18. Инструменты языка
Глава 19. Модули и пакеты
Приложение А. Замечания относительно портирования программ
Приложение Б. Внешние ресурсы, дополняющие стандартную библиотеку
Указатель модулей Python
Предметный указатель

Пример страницы из книги
Пример страницы из книги