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