Архив метки: docker

Как остановить и удалить все контейнеры и образы в Docker

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

Топ-10 книг по Kubernetes на русском языке: выбирайте лучшие и развивайтесь в автоматизации и оркестрации приложений

Топ-10 книг по Kubernetes на русском языке: выбирайте лучшие и развивайтесь в автоматизации и оркестрации приложений

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

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

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

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

Как использовать SQLAlchemy в приложениях Flask? Полное руководство с примерами и объяснениями

Полное руководство по использованию SQLAlchemy в приложениях Flask

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

В этой статье мы рассмотрим, как использовать SQLAlchemy в приложениях Flask. Мы начнём с основных концепций, таких как создание моделей данных и настройка соединений с базой данных, а также проясним, что такое объектно-реляционное отображение (ORM). Затем мы рассмотрим некоторые распространённые задачи, такие как создание, чтение, обновление и удаление данных из базы данных, а также связи между таблицами и фильтрацию данных.

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

Использование SQLAlchemy в приложениях Flask

Если вы разрабатываете веб-приложение на Flask, то не обойтись без работы с базой данных. SQLAlchemy является одним из наиболее популярных инструментов работы с БД в Python. Он предоставляет уровень абстракции, который позволяет работать с БД, не заботясь о деталях реализации для конкретных СУБД.

Для интеграции SQLAlchemy в приложение Flask достаточно выполнить несколько шагов. Сначала необходимо создать экземпляр класса SQLAlchemy:

from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

db = SQLAlchemy(app)

Затем, в качестве аргумента app указывается экземпляр приложения Flask. Теперь вы можете описать модели данных с помощью SQLAlchemy:

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(80), unique=True, nullable=False)

def __repr__(self):

return '' % self.username

В примере выше мы определяем класс User, который наследуется от базового класса db.Model. С помощью db.Column определяется структура таблицы. Например, определяется первичный ключ (primary_key=True), название поля (username), тип данных (db.String(80)), а также указывается, что поле является уникальным (unique=True) и не может быть пустым (nullable=False).

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

Благодаря уровню абстракции, SQLAlchemy делает работу с БД удобной и эффективной. Вместо того чтобы проводить множество SQL-операций, вы можете работать с высокоуровневыми функциями, такими как add(), delete(), query().

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

Что такое SQLAlchemy?

Что такое SQLAlchemy?

SQLAlchemy – это библиотека для работы с базами данных на языке Python. Она предоставляет инструменты для создания, управления и манипулирования базами данных с помощью объектно-ориентированного подхода. SQLAlchemy позволяет работать с SQL базами данных (например, PostgreSQL, MySQL) и NoSQL базами данных (например, MongoDB) с помощью общего интерфейса.

Основные возможности SQLAlchemy:

  • Создание и управление схемой базы данных с помощью объектов Python.
  • Создание запросов к базе данных на языке Python.
  • Использование высокоуровневого API для упрощения запросов и манипуляций с данными.
  • Поддержка транзакций и блокировок.
  • Поддержка ORM (Object-Relational Mapping) – сопоставление объектов Python с записями в таблицах базы данных.

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

Установка и настройка

Для использования SQLAlchemy в приложениях Flask сначала нужно установить библиотеку. Это можно сделать с помощью утилиты pip, выполнив следующую команду:

pip install flask-sqlalchemy

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

pip install psycopg2

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

  1. Импортировать класс SQLAlchemy из библиотеки flask_sqlalchemy:
  2. from flask_sqlalchemy import SQLAlchemy

  3. Создать объект класса:
  4. db = SQLAlchemy(app)

  5. Задать путь для доступа к БД:
  6. app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘postgresql://username:password@localhost/dbname’

  7. При необходимости задать флаг для отслеживания изменений:
  8. app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False

  9. При необходимости указать стандартное имя таблицы:
  10. app.config[‘SQLALCHEMY_TABLENAME_PREFIX’] = ‘prefix_’

После настройки приложения можно приступить к созданию моделей и работе с БД.

Установка SQLAlchemy

Для работы с SQLAlchemy в приложениях Flask необходимо выполнить установку данной библиотеки. Существует несколько способов ее установки.

  • Используя Pip: Для установки воспользуйтесь командой: pip install SQLAlchemy
  • Используя Anaconda: Если вы используете Anaconda, то можно выполнить установку командой: conda install sqlalchemy
  • Используя Docker: Если вы устанавливаете приложение в Docker-контейнере, то установку SQLAlchemy можно выполнить через Dockerfile с помощью команды: RUN pip install SQLAlchemy

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

Подключение к БД

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

В первую очередь, установим драйвер для базы данных, с которой будем работать. Например, если мы будем использовать MySQL, нужно установить драйвер mysql-connector-python:

pip install mysql-connector-python

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

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

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

SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://username:password@host/db_name'

Здесь мы указываем тип базы данных (mysql), имя пользователя, пароль, хост и имя базы данных.

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

SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://username:password@host/db_name?charset=utf8'

После этого мы можем инициализировать наше приложение и передать ему нашу базу данных:

from flask import Flask

app = Flask(__name__)

app.config.from_pyfile('config.py')

db.init_app(app)

Теперь мы можем использовать нашу базу данных в нашем приложении.

Основы работы с SQLAlchemy

SQLAlchemy – это популярный инструмент для работы с базами данных в Python. Он предоставляет объектно-реляционный маппер (ORM), позволяющий работать с базой данных, используя объекты Python, а не SQL запросы. Вместо того, чтобы писать SQL запросы, можно создавать классы, соответствующие таблицам в базе данных, и осуществлять CRUD-операции с помощью методов ORM.

Основным объектом в SQLAlchemy является Session, которая обеспечивает подключение к базе данных и хранит объекты ORM. Session позволяет начать транзакцию, выполнить запросы к базе данных и зафиксировать изменения.

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

from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'

db = SQLAlchemy(app)

В данном примере создается объект Flask, устанавливается параметр подключения к базе данных и создается объект SQLAlchemy.

Для создания модели таблицы в SQLAlchemy необходимо создать класс, унаследованный от db.Model. Класс определяет поля таблицы и их тип данных:

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(80), unique=True, nullable=False)

email = db.Column(db.String(120), unique=True, nullable=False)

В данном примере создается модель таблицы User, которая содержит поля id, username и email. id является первичным ключом, username и email являются уникальными и ненулевыми.

Основные методы ORM-объектов SQLAlchemy:

  • query.filter() – выборка строк по заданному условию
  • query.all() – выборка всех строк из таблицы
  • query.first() – выборка первой строки из таблицы
  • query.order_by() – сортировка строк по заданному полю
  • query.limit() – ограничение количества выбираемых строк
  • query.offset() – сдвиг начала выборки относительно начала таблицы

Это основные методы для получения данных из таблицы. Они возвращают объекты ORM, которые можно изменять или удалить из базы данных. Для добавления новой записи в базу данных необходимо создать объект ORM, заполнить его поля и добавить его в Session:

user = User(username='John', email='john@example.com')

db.session.add(user)

db.session.commit()

В данном примере создается объект User, заполняются его поля и добавляется в Session. Метод commit() фиксирует изменения в базе данных.

Создание моделей

Модели в Flask создаются с помощью библиотеки SQLAlchemy. В SQLAlchemy модель представляет собой класс, который наследуется от базового класса из sqlalchemy.ext.declarative модуля. Этот базовый класс предоставляет нам возможность создавать модели со свойствами, которые могут быть дескрипторами столбцов в базе данных.

Создание модели

Простой пример модели для таблицы пользователей:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

name = db.Column(db.String(100))

email = db.Column(db.String(100), unique=True)

password = db.Column(db.String(100))

Здесь мы определяем модель User, которая имеет четыре свойства – id, name, email и password. С помощью db.Column мы указываем, что каждый атрибут является столбцом в базе данных. Мы также указали, что id является первичным ключом таблицы.

Создание связей

Одной из сильных сторон SQLAlchemy является возможность создавать связи между таблицами. Например, мы можем создать модель Post, которая ссылается на модель User:

class Post(db.Model):

id = db.Column(db.Integer, primary_key=True)

title = db.Column(db.String(100))

text = db.Column(db.String(500))

user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

user = db.relationship('User', backref=db.backref('posts', lazy='dynamic'))

Здесь мы добавили user_id, который является внешним ключом User. Мы также создали связь с моделью User, используя db.relationship. backref ‘posts’ создает свойство posts в объекте класса User, свойство которого возвращает список всех постов, созданных этим пользователем.

Создание таблиц

Чтобы создать соответствующую таблицу в базе данных, нам нужно вызвать метод create_all() объекта db:

db.create_all()

Это создаст все таблицы моделей, определенных в приложении. Если мы захотим изменить структуру базы данных, мы можем просто обновить определение модели и вызвать метод create_all() снова, чтобы обновить таблицы.

Добавление данных

SQLAlchemy позволяет просто и удобно добавлять данные в базу данных, используя объекты классов моделей. Для того, чтобы добавить объект в базу данных, необходимо сначала создать экземпляр класса модели и заполнить его атрибуты:

from app import db

from app.models import Item

item = Item(name='Название', description='Описание')

Затем нужно добавить объект в сессию и сохранить изменения в базе данных с помощью методов add и commit:

db.session.add(item)

db.session.commit()

Также можно добавить несколько объектов одновременно, используя метод add_all:

items = [

Item(name='Название 1', description='Описание 1'),

Item(name='Название 2', description='Описание 2')

]

db.session.add_all(items)

db.session.commit()

Стоит отметить, что перед выполнением команды commit данные не будут сохранены в базе данных. Только после выполнения метода commit изменения будут по-настоящему сохранены.

Выборка данных

Для выборки данных из базы данных, в SQLAlchemy используется метод query(). Он позволяет сформировать запрос с помощью фильтрации, сортировки и группировки данных.

Например, чтобы получить все записи таблицы users, нужно вызвать метод all() после метода query():

from models import User

users = User.query.all()

Если нужно получить только определенные записи, можно использовать метод filter(). Он принимает аргументы в формате фильтра:

users = User.query.filter_by(username='admin').all()

Чтобы отсортировать полученный список, можно использовать метод order_by(). Он принимает поля, по которым нужно отсортировать данные:

users = User.query.order_by(User.username.desc()).all()

Для группировки данных, можно использовать метод group_by(). Он принимает поля, по которым нужно сгруппировать данные:

users = User.query.group_by(User.role).all()

Для более сложных запросов можно использовать метод join() для объединения таблиц. Он принимает объекты таблиц, которые нужно объединить:

from models import User, Post

users_posts = User.query.join(Post).all()

Также, для получения конкретных полей таблицы, можно использовать метод with_entities(). Он принимает имена полей, которые нужно получить:

usernames = User.query.with_entities(User.username).all()

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

Расширенные возможности SQLAlchemy

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

Одной из главных возможностей SQLAlchemy является поддержка нескольких типов соединений к базам данных, включая PostgreSQL, MySQL, SQLite, Oracle и другие. SQLAlchemy позволяет использовать разные драйверы для каждого из типов соединений, что упрощает работу с различными БД.

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

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

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

Связи между таблицами

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

В SQLAlchemy есть три типа отношений:

  • Один к одному (One-to-One) – когда у каждой записи в одной таблице есть только одна связанная запись в другой таблице;
  • Один ко многим (One-to-Many) – когда у каждой записи в одной таблице может быть несколько связанных записей в другой таблице;
  • Многие ко многим (Many-to-Many) – когда у каждой записи в одной таблице может быть несколько связанных записей в другой таблице, и наоборот.

Чтобы объявить отношение между двумя таблицами, необходимо использовать специальные инструкции в классах, которые отображают таблицы в SQLAlchemy.

Например, для создания отношения “один ко многим” необходимо определить свойство relationship() в классе-модели. Пример:

class Author(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    books = db.relationship(‘Book’, backref=’author’, lazy=True)

  • books – свойство модели, хранящее список книг автора;
  • backref – указывает, как связанные записи будут отображаться на объект-родитель. В данном случае, автор будет иметь свойство books, которое будет возвращать список его книг;
  • lazy – определяет стратегию загрузки связанных записей. В данном случае, связи будут загружаться только по требованию (lazy=’dynamic’).

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

Транзакции и блокировки

В приложениях Flask, работающих с базами данных, важным аспектом является правильное использование транзакций и блокировок. Транзакции – это совокупность операций, которые либо выполняются полностью, либо не выполняются вообще. Блокировки используются для предотвращения одновременного доступа к изменяемым данным.

В SQLAlchemy транзакции автоматически управляются, если вы используете стандартное соединение с базой данных. Достаточно начать транзакцию с помощью метода begin() у экземпляра класса Session, выполнить все нужные операции внутри транзакции, и завершить ее методом commit(). В случае возникновения ошибки, транзакция автоматически откатывается.

Блокировки – это способ предотвращения одновременного доступа к изменяемым данным из нескольких потоков или процессов. Они используются в тех случаях, когда два или более пользователей попытаются изменять один и тот же объект одновременно. SQLAlchemy поддерживает несколько режимов блокировки:

  • shared: разделенная блокировка, позволяющая нескольким пользователям читать один объект одновременно, но блокирующая его для записи.
  • update: блокировка на запись, позволяющая только одному пользователю изменять объект в данный момент.
  • exclusive: эксклюзивная блокировка, которая блокирует доступ к объекту для всех других пользователей. Используется при операциях с высоким риском для данных.

Для использования блокировок в SQLAlchemy можно использовать аргументы функции with_for_update() или with_for_update(nowait=True), если вы хотите, чтобы запрос завершился с ошибкой, если блокировка уже была установлена другим процессом в данный момент.

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

Использование ORM

ORM (Object-Relational Mapping) – это технология, которая позволяет работать с базой данных, используя объекты и методы. Вместо того чтобы писать SQL-запросы к базе данных, мы можем использовать ORM и работать с базой данных на уровне объектов.

В Flask ORM включен SQLAlchemy, один из самых популярных ORM-фреймворков для Python. Он позволяет работать с различными СУБД, такими как MySQL, PostgreSQL, SQLite и др. SQLAlchemy позволяет не только работать с базой данных, но также описывать ее с помощью классов Python.

Пример создания модели класса для таблицы в базе данных:

from flask_sqlalchemy import SQLAlchemy

from flask import Flask

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/db_name'

db = SQLAlchemy(app)

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(80), unique=True, nullable=False)

email = db.Column(db.String(120), unique=True, nullable=False)

def __repr__(self):

return '' % self.username

В данном примере мы создали класс User, который описывает таблицу user в базе данных. В модели класса мы определили поля таблицы – id, username, email, а также определен метод __repr__, который возвращают строковое представление объекта.

Для сохранения объекта в базу данных используется метод add:

new_user = User(username='john', email='john@example.com')

db.session.add(new_user)

db.session.commit()

Метод commit() сохраняет изменения в базе данных.

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

Примеры использования

SQLAlchemy является мощным инструментом для работы с базами данных в Flask-приложениях. Вот несколько примеров использования:

  • Создание моделей данных: SQLAlchemy позволяет создавать модели данных с помощью Python классов. Например, мы можем создать класс “User”, который будет представлять пользователей нашего приложения:
    • class User(db.Model):
    • id = db.Column(db.Integer, primary_key=True)
    • username = db.Column(db.String(100), unique=True)
    • email = db.Column(db.String(120), unique=True)
  • Запросы к базе данных: SQLAlchemy позволяет выполнять запросы к базе данных с помощью методов Python. Например, мы можем получить список всех пользователей нашего приложения:
    • users = User.query.all()
  • Создание отношений между таблицами: SQLAlchemy позволяет создавать отношения между таблицами базы данных с помощью свойств моделей данных. Например, мы можем добавить отношение “один ко многим” между таблицами пользователей и их постами:
    • class Post(db.Model):
    • id = db.Column(db.Integer, primary_key=True)
    • title = db.Column(db.String(100))
    • content = db.Column(db.Text)
    • user_id = db.Column(db.Integer, db.ForeignKey(‘user.id’))
  • Использование транзакций: SQLAlchemy позволяет использовать транзакции для выполнения группы операций над базой данных в единой транзакции. Например, мы можем создать нового пользователя и добавить его пост в одной транзакции:
    • with db.session.begin_nested():
    • user = User(username=’john’, email=’john@example.com’)
    • db.session.add(user)
    • post = Post(title=’Hello, World!’, content=’This is my first post’, user=user)
    • db.session.add(post)
    • db.session.commit()

Пример 1: создание простого приложения

Для создания простого приложения Flask с использованием SQLAlchemy вам необходимо сделать несколько шагов:

  • Установить Flask и SQLAlchemy через pip.
  • Создать файл с расширением .py, в котором будет расположен код вашего приложения.
  • Начать задавать параметры вашего приложения.

Вот пример кода для создания приложения:

from flask import Flask

from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'

db = SQLAlchemy(app)

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(80), unique=True)

email = db.Column(db.String(120), unique=True)

def __init__(self, username, email):

self.username = username

self.email = email

@app.route('/')

def home():

return "Hello, World!"

if __name__ == '__main__':

app.run(debug=True)

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

Для запуска приложения мы используем метод app.run с обязательным параметром debug=True. Это знакомит Flask с тем, что вам может понадобится отладка приложения в процессе разработки.

Пользоваться приложением можно по адресу http://127.0.0.1:5000/

Пример 2: более сложное приложение с использованием ORM

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

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

Для этого создадим класс Product, который будет являться наследником класса db.Model, и определим все необходимые поля:

class Product(db.Model):

id = db.Column(db.Integer, primary_key=True)

name = db.Column(db.String(255))

category = db.Column(db.String(255))

description = db.Column(db.Text)

price = db.Column(db.Float)

quantity = db.Column(db.Integer)

Теперь нам нужно определить роуты, которые будут отображать каталог продуктов и позволять добавлять новые товары. Определим два роута: /products для отображения каталога и /products/new для добавления новых товаров.

В роуте /products мы будем запрашивать список всех продуктов из базы данных и передавать его в шаблон для отображения:

@app.route('/products')

def products():

products = Product.query.all()

return render_template('products.html', products=products)

А в роуте /products/new мы будем обрабатывать POST запрос с переданными наименованием, категорией, описанием, ценой и количеством товара и добавлять их в базу данных:

@app.route('/products/new', methods=['GET', 'POST'])

def new_product():

if request.method == 'POST':

name = request.form['name']

category = request.form['category']

description = request.form['description']

price = float(request.form['price'])

quantity = int(request.form['quantity'])

product = Product(name=name, category=category, description=description, price=price, quantity=quantity)

db.session.add(product)

db.session.commit()

flash('Product added successfully!', 'success')

return redirect(url_for('products'))

return render_template('new_product.html')

Теперь у нас есть приложение на Flask с использованием ORM SQLAlchemy для управления базой данных. Это всего лишь пример, но вы можете использовать те же принципы для создания более сложных приложений с большим числом моделей и роутов.

Оптимизация работы с SQLAlchemy в Flask

1. Использование индексов

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

2. Выбор правильного типа данных

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

3. Использование сессий

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

4. Оптимизация запросов

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

5. Использование кэширования

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

6. Работа с большими объемами данных

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

Использование flask_sqlalchemy

Использование flask_sqlalchemy

Flask_sqlalchemy – это расширение Flask для работы с базами данных с помощью SQLAlchemy. Оно предоставляет простой и удобный способ связи Flask приложений с базами данных.

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

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

Пример инициализации и настройки flask_sqlalchemy:

from flask_sqlalchemy import SQLAlchemy

from flask import Flask

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@localhost/mydatabase'

db = SQLAlchemy(app)

После инициализации, можно создать модели данных для таблиц:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(80), unique=True, nullable=False)

email = db.Column(db.String(120), unique=True, nullable=False)

def __repr__(self):

return '' % self.username

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

from app import db

class Post(db.Model):

id = db.Column(db.Integer, primary_key=True)

title = db.Column(db.String(80), nullable=False)

content = db.Column(db.String(120), nullable=False)

author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

author = db.relationship('User', backref=db.backref('posts', lazy=True))

def __repr__(self):

return '' % self.title

author = User.query.filter_by(username='john').first()

posts = author.posts.all()

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

Кеширование запросов

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

В Flask есть несколько библиотек для кеширования, таких как Flask-Caching и Flask-Cache. При использовании SQLAlchemy можно использовать встроенный кеш-механизм.

SQLAlchemy предоставляет возможность кеширования запросов через объект session. Для этого нужно установить и настроить кеш-бэкенд, например, используя библиотеку memcached, и передать его в объект session через аргумент cache_impl.

from sqlalchemy import create_engine

from sqlalchemy.orm import sessionmaker

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy.orm import scoped_session

from sqlalchemy.orm import sessionmaker

from werkzeug.contrib.cache import MemcachedCache

Base = declarative_base()

engine = create_engine('postgresql://user:password@localhost/dbname')

cache = MemcachedCache(['127.0.0.1:11211'])

Session = scoped_session(sessionmaker(bind=engine, cache_impl=cache))

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

Дополнительные материалы по SQLAlchemy

SQLAlchemy ORM Documentation

Документация SQLAlchemy ORM предоставляет подробную информацию о том, как использовать ORM в приложениях, а также описывает все доступные функции и методы. Это полезный ресурс, если вы хотите углубиться в детали SQLAlchemy ORM.

SQLAlchemy Core Tutorial

SQLAlchemy Core – это низкоуровневый компонент SQLAlchemy, который позволяет вам работать с базами данных на более низком уровне, чем ORM. Этот туториал предоставляет подробную информацию о том, как использовать SQLAlchemy Core и как выполнить базовые операции с базами данных.

SQLAlchemy и Flask-Script Tutorial

Flask-Script – это расширение Flask, которое позволяет управлять вашим приложением Flask из командной строки. В этом туториале описывается, как использовать SQLAlchemy в приложениях Flask с помощью Flask-Script.

SQLAlchemy и Flask-Migrate Tutorial

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

  • SQLAlchemy Cheatsheet: Шпаргалка для SQLAlchemy.
  • The SQL Expression Language: Reference: Справочник SQL Expression Language – низкоуровневого SQL-интерфейса SQLAlchemy.
  • SQLAlchemy и Alembic: Основы Alembic – миграции данных с SQLAlchemy и Flask.

Вопрос-ответ:

Что такое SQLAlchemy?

SQLAlchemy – это библиотека Python, которая предоставляет ORM-фреймворк и набор инструментов для работы с базами данных. Она позволяет разработчикам использовать объектно-ориентированный подход при работе с данными из базы данных в приложениях Flask.

Какие основные компоненты входят в SQLAlchemy?

SQLAlchemy состоит из нескольких компонентов: ORM (Object-Relational Mapping), Core (низкоуровневый доступ к базе данных), Expression Language (язык для создания запросов к базе данных) и множество инструментов для работы с данными и миграций баз данных.

Как подключить SQLAlchemy к приложению Flask?

Для подключения SQLAlchemy к приложению Flask необходимо установить библиотеку и создать объект приложения Flask. Затем необходимо инициализировать расширение SQLAlchemy и настроить параметры подключения к базе данных в указанном формате: ‘dialect+driver://username:password@host:port/database’. Далее можно создавать модели данных и использовать их в приложении.

Какие типы данных поддерживает SQLAlchemy?

SQLAlchemy поддерживает большинство базовых типов данных, таких как integer, string, date, time, boolean, а также дополнительные типы данных, такие как JSON, XML, UUID и др. Кроме того, можно создавать собственные типы данных для работы с определенными форматами данных.

Как использовать SQLAlchemy для работы с множеством баз данных?

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

Как выполнить миграции базы данных с помощью SQLAlchemy?

SQLAlchemy поддерживает механизм миграций базы данных. Для этого необходимо установить дополнительное расширение Alembic и настроить его в проекте. Затем можно создавать миграционные скрипты и использовать их для обновления базы данных в соответствии с изменениями в моделях данных. Например, добавление новой таблицы в базу данных или изменение типа данных в столбце.

Видео:

Сообщение Как использовать SQLAlchemy в приложениях Flask? Полное руководство с примерами и объяснениями появились сначала на Программирование на Python.

Как создать схему в SQLAlchemy ORM: подробное руководство

Как создать схему в SQLAlchemy ORM: подробное руководство

SQLAlchemy – это инструмент для работы с реляционными базами данных в языке Python, который позволяет работать с базами данных, используя объекты, а не язык SQL. Он предоставляет удобные средства для работы с ORM, которые позволяют создавать схему таблиц в объектно-ориентированном стиле.

Данная статья расскажет о том, как создать схему таблиц с использованием SQLAlchemy ORM. В ней будут рассмотрены базовые сущности модели данных, такие как таблицы, колонки, отношения между таблицами, а также более продвинутые возможности библиотеки, такие как каскадное удаление и обновление данных.

Для начала работы с библиотекой SQLAlchemy необходимо установить ее с помощью менеджера пакетов Python. После установки необходимо настроить соединение с базой данных, определив соответствующие параметры. Затем можно приступить к созданию модели данных и определению таблиц и колонок.

Эта статья прекрасно подходит как для начинающих, так и для опытных разработчиков Python. Если вы желаете научиться создавать свои собственные модели данных с помощью SQLAlchemy ORM, то эта статья для вас.

Что такое SQLAlchemy ORM

SqlAlchemy — это библиотека для работы с базами данных в языке Python. Она позволяет создавать объектно-реляционную модель (ORM).

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

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

При разработке приложений на Python, SqlAlchemy ORM является важным инструментом, позволяющим разрабатывать приложения на Python с базами данных быстро и удобно

Описание

SQLAlchemy ORM – это инструмент для создания объектно-реляционной маппинговой системы, позволяющий связать базу данных и приложение. Он позволяет определить модели данных, соответствующие таблицам базы данных, и создавать объекты, которые могут быть использованы для взаимодействия с базой данных.

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

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

Схема в SQLAlchemy ORM создается путем вызова метода create_all () объекта MetaData, который включает все определенные модели данных. После этого приложение может использовать созданную схему для взаимодействия с базой данных.

Преимущества

Использование SQLAlchemy ORM при создании схемы базы данных имеет ряд преимуществ, среди которых:

  • Удобство и простота: SQLAlchemy ORM позволяет работать с базой данных на уровне объектов, что существенно упрощает процесс ее создания и изменения.
  • Безопасность и надежность: ORM предоставляет механизмы защиты от SQL-инъекций, что делает базу данных более надежной и безопасной.
  • Поддержка различных СУБД: SQLAlchemy ORM поддерживает множество СУБД, что позволяет использовать ее в различных проектах без необходимости переписывания кода.
  • Гибкость: ORM предоставляет широкие возможности для настройки схемы базы данных и работы с данными, позволяя реализовывать различные сценарии.
  • Абстракция от СУБД: ORM абстрагируется от конкретной СУБД, что позволяет разработчикам использовать ее без необходимости знать детали работы той или иной СУБД.

В целом, использование SQLAlchemy ORM при создании схемы базы данных существенно упрощает и ускоряет процесс разработки, повышает безопасность и надежность базы данных, а также обеспечивает гибкость и надежно работает с различными СУБД.

Создание базы данных

Прежде чем начать работу с объектно-реляционной моделью SQLAlchemy, необходимо создать базу данных, в которой будут храниться данные. Для этого можно воспользоваться любой системой управления базами данных, поддерживаемой SQLAlchemy, например, MySQL, PostgreSQL или SQLite.

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

После определения модели данных необходимо выполнить операцию создания схемы в базе. Для этого можно воспользоваться методом create_all из модуля sqlalchemy.schema. Пример кода:

from sqlalchemy import create_engine, Column, Integer, String

from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('postgresql://user:password@localhost:5432/mydatabase')

Base = declarative_base()

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

age = Column(Integer)

Base.metadata.create_all(engine)

В данном примере создается база данных с именем mydatabase в PostgreSQL. Определяется класс User, который представляет таблицу users в базе. В классе User определены три поля: id, name и age. Метод create_all выполняет создание схемы в базе данных.

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

Установка SQLAlchemy

Для работы с SQLAlchemy необходимо установить библиотеку. Существует несколько вариантов установки:

  • стандартная установка с помощью pip
  • установка через Anaconda
  • установка через Docker

Производится установка для Python версии 3 или выше. Для установки с помощью pip необходимо выполнить команду:

pip install sqlalchemy

Для установки через Anaconda необходимо выполнить команду:

conda install sqlalchemy

Если же вы используете Docker, то необходимо выбрать образ с предустановленной библиотекой, например:

docker run -it python:3-slim-buster

После установки библиотеки можно приступать к созданию схемы в SQLAlchemy ORM.

Создание базы данных через ORM

Создание базы данных через ORM

ORM – объектно-реляционное отображение – позволяет упростить работу с базами данных, а именно создание, чтение, обновление и удаление записей из таблиц. SQLAlchemy – это одна из самых популярных библиотек на языке Python для работы с базами данных через ORM.

Для создания базы данных через SQLAlchemy ORM необходимо определить модели данных. Модель – это класс, который соответствует таблице в базе данных. В классе определены поля, которые являются атрибутами таблицы, а их типы данных – типами данных столбцов таблицы. Также необходимо определить как связаны таблицы между собой.

Пример модели данных:

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy import Column, Integer, String, ForeignKey

from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

username = Column(String(50), unique=True)

email = Column(String(120), unique=True)

password = Column(String(50))

posts = relationship("Post", back_populates="author")

class Post(Base):

__tablename__ = 'posts'

id = Column(Integer, primary_key=True)

title = Column(String(50))

description = Column(String(120))

user_id = Column(Integer, ForeignKey('users.id'))

author = relationship("User", back_populates="posts")

Для создания таблиц в базе данных необходимо вызвать метод create_all объекта класса Base:

from sqlalchemy import create_engine

engine = create_engine('sqlite:///example.db')

Base.metadata.create_all(engine)

В данном примере создается база данных SQLite соединение с названием example.db и создаются таблицы, соответствующие определенным классам.

Таким образом, создание базы данных через SQLAlchemy ORM является простым и удобным процессом и позволяет сократить время на разработку проектов, связанных с базами данных.

Создание таблиц

Создание таблиц с помощью SQLAlchemy ORM довольно просто. Для этого необходимо определить классы, которые будут представлять таблицы в базе данных.

Прежде всего, необходимо определить базовый класс модели. Обычно он наследуется от класса declarative_base() из модуля sqlalchemy.ext.declarative. Этот базовый класс предоставляет пару полезных методов, в том числе метод query(), который позволяет делать запросы в базу данных.

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

Для определения атрибутов используются различные типы данных, например: Integer, String, Boolean, DateTime и т.д. Кроме того, можно использовать такие параметры, как primary_key, unique, nullable и другие, чтобы задать различные свойства поля.

Пример определения класса таблицы:

from sqlalchemy import Column, Integer, String

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

age = Column(Integer)

В данном примере определен класс User, который будет соответствовать таблице users в базе данных. Класс содержит три атрибута: id, name и age, каждый из которых является полем таблицы. Атрибут id также является первичным ключом.

Описание объекта таблицы

При создании схемы в SQLAlchemy ORM важно определить объекты таблицы. Объект таблицы представляет собой описание сущности, которую вы хотите хранить в базе данных. Объект таблицы содержит набор полей и правил, определяющих, как эти поля могут быть заполнены.

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

Объекты таблицы могут также содержать ограничения, которые определяют допустимые значения для каждого поля. Например, вы можете определить, что поле “возраст” может быть заполнено только числами в определенном диапазоне. Также можно определить, что поле “имя” может содержать только буквенные символы.

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

Создание таблицы через ORM

Одна из основных возможностей SQLAlchemy ORM – создание таблиц базы данных без написания непосредственного SQL запроса.

Для создания таблицы через ORM нужно определить соответствующий класс, который будет представлять таблицу. Например, для создания таблицы “users” можно определить следующий класс:

  • Класс: User
  • Описание: представляет таблицу “users”
  • Атрибуты: id, name, email

from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy import Column, Integer, String

Base = declarative_base()

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

email = Column(String)

В приведенном примере используется базовый класс declarative_base() для определения базовых функций ORM, а затем создается класс User с определением имени таблицы __tablename__, а также соответствующими атрибутами в виде столбцов (Columns).

После определения класса можно использовать метод create_all() для создания соответствующей таблицы в базе данных:

from sqlalchemy import create_engine

engine = create_engine('postgresql://user:password@localhost/mydatabase')

Base.metadata.create_all(engine)

В данном примере создается экземпляр класса create_engine для работы с PostgreSQL базой данных. Затем вызывается метод create_all() с передачей ранее определенного базового класса (Base) в качестве параметра для создания таблицы базы данных.

Таким образом, определение класса и использование метода create_all() предоставляют удобный способ создать таблицу в базе данных с помощью SQLAlchemy ORM, без написания сложных SQL запросов.

Определение столбцов

Основная задача определения столбцов – это задание имени и типа каждого столбца в таблице базы данных. В SQLAlchemy ORM это делается с помощью класса Column.

Пример определения столбца:

from sqlalchemy import Column, Integer, String

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

age = Column(Integer)

  • Определение столбца начинается с указания имени столбца. В примере выше, ему были даны имена id, name и age.
  • Далее необходимо определить тип данных столбца. В данном случае мы использовали типы Integer и String, но SQLAlchemy ORM предоставляет множество других типов данных, таких как Boolean, DateTime и другие.
  • Также может быть указано несколько параметров столбца, таких как primary_key, nullable, unique и другие. В приведенном выше примере мы указали primary_key для столбца id, что означает, что он будет использоваться в качестве первичного ключа для таблицы.

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

Пример:

from sqlalchemy import Column, Integer, String, func

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

age = Column(Integer)

created_at = Column(DateTime, default=func.now())

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

Типы столбцов

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

1. Integer

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

from sqlalchemy import Integer

from sqlalchemy import Column

class MyTable(Base):

__tablename__ = 'mytable'

id = Column(Integer, primary_key=True)

2. String

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

from sqlalchemy import String

from sqlalchemy import Column

class MyTable(Base):

__tablename__ = 'mytable'

name = Column(String(50)) # столбец для хранения строк, длиной не более 50 символов

3. Boolean

Тип данных, предназначенный для хранения значения “истина” или “ложь”. Данный тип может быть полезен при хранении значений булевого типа, например, для определения состояния какого-либо флага. Для определения столбца типа Boolean используется следующий код:

from sqlalchemy import Boolean

from sqlalchemy import Column

class MyTable(Base):

__tablename__ = 'mytable'

is_active = Column(Boolean)

4. DateTime

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

from sqlalchemy import DateTime

from sqlalchemy import Column

class MyTable(Base):

__tablename__ = 'mytable'

created_at = Column(DateTime)

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

Определение столбцов через ORM

С помощью SQLAlchemy ORM можно определить структуру таблицы и ее поля в виде классов Python. Для создания столбцов в таблице используется класс Column из модуля SQLAlchemy. Он принимает два параметра:

  • имя столбца
  • тип данных столбца

Например, чтобы создать таблицу с полями id, name и age, нужно создать класс, который будет описывать эту таблицу:

from sqlalchemy import Column, Integer, String

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

age = Column(Integer)

Здесь мы определяем таблицу users и ее столбцы id, name и age. Параметр primary_key указывает на то, что это первичный ключ таблицы.

Типы данных столбцов соответствуют типам данных в базе данных. Например, Integer соответствует целым числам, а String – строкам. Также можно использовать другие типы данных, такие как Boolean, DateTime, Text и т.д.

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

Также можно определять связи между таблицами и использовать множество других возможностей SQLAlchemy ORM для создания сложных моделей данных.

Определение отношений между таблицами

Один из важных аспектов при создании базы данных – правильное определение отношений между таблицами. В SQLAlchemy ORM это можно сделать с помощью соответствующих свойств и методов.

Одно из самых простых отношений между таблицами – связь один к многим (one-to-many). Например, у нас есть таблица “Категории товаров” и таблица “Товары”. Одна категория может содержать много товаров, а один товар может относиться только к одной категории. В таком случае в модели объектно-реляционной маппинга (ORM) мы используем поле relationship.

Для примера, определим модели таблиц “Категории товаров” и “Товары” следующим образом:

Model CategoryModel Product
  • category_id (Primary Key)
  • name
  • Products (relationship)
  • product_id (Primary Key)
  • name
  • description
  • price
  • category_id (Foreign Key)

Выше видно, что у модели Category есть поле Products, которое относится к модели Product и определяет связь между таблицами.

Также, мы можем использовать свойства backref и cascade в методе relationship для установки обратной ссылки и настройки действий при удалении связанных объектов.

В SQLAlchemy ORM есть и другие типы отношений между таблицами, такие как связи многие-ко-многим (many-to-many) и связи один-к-одному (one-to-one). В них также используются методы relationship и backref, но детали их определения и использования зависят от конкретной задачи в проекте.

Один к одному

Один к одному (One-to-One) – это вид связи между таблицами в базе данных, при котором каждая запись в одной таблице соответствует одной записи в другой таблице и наоборот. Такая связь может быть полезна во многих случаях, например, когда необходимо хранить дополнительную информацию о сущности, но эта информация не обязательна для всех записей.

В SQLAlchemy ORM взаимосвязь «один к одному» может быть создана с помощью отношения relationship(). Она определяет связь между двумя таблицами через свойства объектов, и включает в себя учет внешних ключей.

Пример создания отношения «один к одному» в SQLAlchemy ORM:

  • Создание таблицы User с первичным ключом id, и полем name:
  • User
    id
    name
  • Создание таблицы Profile с первичным ключом id, и полями first_name, last_name, и user_id:
  • Profile
    id
    first_name
    last_name
    user_id (внешний ключ на User.id)
  • Создание отношения между таблицами User и Profile:

class User(Base):

__tablename__ = 'users'

id = Column(Integer, primary_key=True)

name = Column(String)

profile = relationship("Profile", uselist=False, back_populates="user")

class Profile(Base):

__tablename__ = 'profiles'

id = Column(Integer, primary_key=True)

first_name = Column(String)

last_name = Column(String)

user_id = Column(Integer, ForeignKey('users.id'))

user = relationship("User", back_populates="profile")

В этом примере, в таблице User создается свойство profile, чтобы связать каждую запись User с одной записью Profile. Аргумент uselist=False указывает, что связь является «один к одному». Аргумент back_populates указывает, что связанные объекты будут иметь свойство user.

Один ко многим

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

Чтобы определить это отношение в SQLAlchemy ORM, мы нужно использовать связь один-ко-многим (relationship). Эта связь создается в классе, который представляет таблицу с “одними” данными. В нашем случае это класс User. Внутри класса мы добавляем поле, которое представляет отношения между таблицами:

orders = relationship(“Order”, back_populates=”user”)

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

Для того чтобы определить обратную сторону связи (т.е. многие объекты), мы также должны добавить поле в класс Order:

user = relationship(“User”, back_populates=”orders”)

В этом поле мы указываем, какой класс (User) представляет “один” объект, и какое поле в этом классе представляет отношение между таблицами (orders).

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

orders = relationship(“Order”, back_populates=”user”, cascade=”all, delete, delete-orphan”, passive_deletes=True)

Здесь мы указываем, что при удалении пользователя (parent) будут удаляться все связанные с ним заказы (child), а также устанавливаем параметр passive_deletes=True, чтобы SQLAlchemy мог использовать delete cascade, если он поддерживается на уровне базы данных.

В итоге, определение связей “один ко многим” в SQLAlchemy ORM довольно простое. Главное – понимать, как работает механизм связей и какие параметры можно использовать для настройки их поведения.

Многие ко многим

Многие ко многим (Many-to-Many) это связь между двумя таблицами, где каждая запись в одной таблице может быть связана с несколькими записями в другой таблице и наоборот. В SQLAlchemy ORM для создания связи многие ко многим используется конструкция secondary=, которая позволяет создать третью таблицу, которая будет хранить связи между двумя другими таблицами.

Для создания связи многие ко многим в SQLAlchemy ORM необходимо создать три таблицы: таблицу для первой сущности, таблицу для второй сущности и таблицу связей. Например, для связи “многие ко многим” между таблицами “Авторы” и “Книги” необходимо создать три таблицы: “Авторы”, “Книги” и “Авторы_Книги”.

В таблице связей “Авторы_Книги” содержатся два столбца: столбец “автор_id”, который ссылается на таблицу “Авторы” и столбец “книга_id”, который ссылается на таблицу “Книги”. Обратите внимание, что эти столбцы являются внешними ключами для своих таблиц.

Для объявления связи многие ко многим в SQLAlchemy ORM необходимо использовать объекты relationship() и backref(). Например, чтобы определить связь “многие ко многим” между сущностями “Авторы” и “Книги”, нужно в классе “Автор” объявить свойство books = relationship(‘Book’, secondary=‘authors_books’, backref=‘authors’), а в классе “Книга” – свойство authors = relationship(‘Author’, secondary=‘authors_books’, backref=‘books’).

Операции с таблицами и записями

Создание таблиц в SQLAlchemy ORM происходит автоматически при создании моделей. Для работы с таблицами и записями можно использовать такие операции, как CRUD (Create, Read, Update, Delete).

  • Create: Создание новой записи в таблице происходит с помощью метода commit() объекта сессии. Новая запись должна быть предварительно создана с помощью конструктора модели.
  • Read: Чтение данных происходит с помощью методов all(), filter(), count(), и других. Например, для получения всех записей из таблицы необходимо вызвать метод all() объекта сессии и сохранить результат в переменной.
  • Update: Обновление данных в таблице происходит следующим образом: сначала получаем запись, которую нужно обновить, с помощью метода query.filter(). Затем изменяем значения атрибутов модели и вызываем метод commit() объекта сессии.
  • Delete: Удаление записи происходит с помощью метода delete() объекта сессии и метода delete() объекта запроса. С помощью метода query.filter() необходимо получить запись, которую нужно удалить, а затем вызвать метод delete().

Также с помощью SQLAlchemy ORM можно выполнять другие операции, например, объединение таблиц, сортировку данных и группировку записей.

Создание записей

Создание записей

Чтобы создать новую запись в базе данных, необходимо создать объект класса модели и заполнить его необходимыми данными. Например, если у нас есть модель “Пользователь”, то можно создать новую запись следующим образом:

new_user = User(username='JohnDoe', email='johndoe@example.com')

Здесь мы создаем новый объект класса “User” и заполняем его поля “username” и “email”. Для того, чтобы записать этот объект в базу данных, необходимо вызвать метод “add” у соответствующего экземпляра сессии:

db.session.add(new_user)

После этого, чтобы сохранить все изменения в базе данных, нужно вызвать метод “commit”:

db.session.commit()

Теперь новая запись добавлена в базу данных и может быть получена при выполнении запросов.

Если необходимо создать несколько записей одновременно, то можно использовать метод “add_all” и передать ему список объектов:

new_users = [User(username='Alice', email='alice@example.com'), User(username='Bob', email='bob@example.com')]

db.session.add_all(new_users)

db.session.commit()

В данном случае мы создаем два объекта класса “User” и передаем их в метод “add_all”. Затем мы сохраняем изменения в базе данных с помощью метода “commit”.

Важно помнить, что при создании новой записи все её обязательные поля должны быть заполнены. Если какой-то из атрибутов не был задан, то SQLAlchemy выбросит исключение “IntegrityError”.

Обновление записей

Однажды созданные записи могут приобрести новое значение или содержание, что требует обновления в базе данных. В SQLAlchemy ORM обновление записей осуществляется через метод update(), принимающий в качестве параметров словарь с обновленными данными и условие выборки записей, которые должны быть обновлены.

Пример обновления записи пользователя с идентификатором 1, у которого изменилось имя:

  1. Создаем объект User на основе модели ORM:
  2. from sqlalchemy.orm import sessionmaker

    Session = sessionmaker(bind=engine)

    session = Session()

    user = session.query(User).filter(User.id == 1).one()

  3. Изменяем соответствующее поле:
  4. user.name = "Новое имя"

  5. Вызываем метод commit(), чтобы сохранить изменения в базе данных:
  6. session.commit()

Более сложные запросы на обновление записей могут быть созданы через использование метода filter(). Например, мы можем изменить все записи пользователей с именем “John”:

session.query(User).filter(User.name == "John").update({User.name: "Новое имя"}, synchronize_session=False)

session.commit()

Если необходимо обновить несколько полей одновременно, необходимо указать их в словаре:

session.query(User).filter(User.id == 1).update({User.name: "Новое имя", User.email: "new_email@example.com"}, synchronize_session=False)

session.commit()

Удаление записей

Удаление записей из базы данных – одна из важных операций, которые могут понадобиться при работе с SQLAlchemy ORM. В данной ORM операция удаления реализуется методом delete().

Пример:

session.query(User).filter(User.id == 1).delete()

session.commit()

В данном примере происходит удаление записи из таблицы User, где значение поля id равно 1. После удаления необходимо произвести сохранение изменений в базе с помощью метода commit().

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

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

В SQLAlchemy ORM также может использоваться метод filter(), чтобы выбрать набор записей для удаления:

session.query(User).filter(User.age <= 25).delete()

В данном примере удаляются все записи из таблицы User, у которых значение поля age меньше или равно 25.

Также возможно удаление нескольких записей сразу:

session.query(User).filter(User.name.like('%John%')).delete(synchronize_session='fetch')

В данном примере удаляются все записи из таблицы User, где в имени содержится строка ‘John’. Опция synchronize_session=’fetch’ гарантирует, что записи будут удалены из всех объектов сессии, которые соответствуют фильтру.

Вопрос-ответ:

Какие основные преимущества использования SQLAlchemy ORM?

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

Как создать схему базы данных с помощью SQLAlchemy ORM?

Ответ: Для создания схемы базы данных с помощью SQLAlchemy ORM необходимо создать классы, которые будут представлять таблицы в базе данных, используя классы Table и Column. Затем нужно создать объект MetaData, который будет содержать информацию о структуре базы данных. Для создания самих таблиц можно использовать метод create_all объекта MetaData.

Как добавить новые записи в таблицу базы данных с помощью SQLAlchemy ORM?

Ответ: Чтобы добавить новые записи в таблицу базы данных с помощью SQLAlchemy ORM, необходимо создать объект класса, который соответствует таблице, используя конструктор этого класса. Затем можно установить значения атрибутов объекта и вызвать метод add объекта Session. После добавления всех нужных объектов в сессию, необходимо вызвать метод commit для сохранения изменений в базе данных.

Как выполнить запрос к базе данных с помощью SQLAlchemy ORM?

Ответ: Для выполнения запроса к базе данных с помощью SQLAlchemy ORM необходимо создать объект класса Query, который будет представлять запрос. Затем можно добавить фильтры, сортировки и другие операции к этому объекту, используя методы класса Query. Наконец, необходимо вызвать метод all или one объекта Query, чтобы выполнить запрос и получить результаты.

Как установить связи между таблицами в базе данных с помощью SQLAlchemy ORM?

Ответ: Для установки связей между таблицами в базе данных с помощью SQLAlchemy ORM необходимо создать классы, которые представляют таблицы, и определить отношения между ними, используя соответствующие атрибуты, такие как ForeignKey, backref и relationship. Затем можно использовать методы класса Query для получения записей, связанных с другими записями в базе данных.

Как обновить запись в таблице базы данных с помощью SQLAlchemy ORM?

Ответ: Чтобы обновить запись в таблице базы данных с помощью SQLAlchemy ORM, необходимо сначала получить эту запись, используя методы класса Query. Затем нужно изменить значения атрибутов объекта, соответствующего этой записи, и вызвать метод commit объекта Session, чтобы сохранить изменения в базе данных.

Видео:

Сообщение Как создать схему в SQLAlchemy ORM: подробное руководство появились сначала на Программирование на Python.

🐳 Популярные ошибки в конфигурации, которые делают контейнерные приложения уязвимыми для атак

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

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

Итак, мы продолжаем статью 🦊 Современное состояние безопасности CI/CD и как предотвратить распространенные ошибки

Среди них популярны контейнерные приложения, обычно использующие такие технологии, как Docker.

Дальнейшее масштабирование стало возможным с появлением таких технологий, как Kubernetes.

Контейнерные приложения позволяют DevOps-командам поддерживать контейнеры с определенными конфигурациями и версиями приложений.

Эта практика также позволяет командам DevOps реплицировать их столько раз, сколько необходимо, и все это в автоматическом режиме.

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

Однако внедрение новых технологий всегда чревато новыми ошибками и уязвимостями.

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

Какие популярные ошибки в конфигурации делают контейнерные приложения уязвимыми для атак?

Наиболее распространенным источником уязвимостей в таких технологиях, как Docker, Kubernetes и других технологиях автоматизации, таких как SaltStack, Ansible и Puppet, являются устаревшие версии программного обеспечения, а также отсутствие процедур усиления безопасности и надлежащего анализа конфигурации.

Права

Одна из самых основных форм неправильной конфигурации в Docker связана с повышением прав пользователя.

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

🐳 Почему процессы в контейнерах Docker не должны запускаться от имени Root

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

🐳 Что такое Docker без root (rootless)?

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

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

Docker поддерживает работу в режиме пользователя rootless/non-root, что позволяет значительно повысить уровень безопасности, конфигурацию которого можно увидеть в официальном руководстве по Docker.

Безопасность данных/конфигурации

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

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

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

Хранение учетных данных – еще одна частая ошибка конфигурации.

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

Монтирование данных вне контейнера легко выполняется с помощью Docker.

Рассмотрим следующую команду Docker run:

docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started

В этом примере данные хранятся вне контейнера по пути /etc/todos – таким образом, контейнер работает независимо, позволяя создавать, уничтожать или перемещать контейнер, сохраняя данные как есть и в отдельном пути.

Автоматизация безопасности

Такие технологии, как Ansible, SaltStack и Puppet, используются для автоматизации задач, которые необходимо выполнять на большом количестве серверов.

Эти технологии используют файлы конфигурации, называемые “плейбуки”, которые содержат информацию о том, что и где должно быть выполнено.

Для работы этих плейбуков необходим доступ к серверам через SSH или аналогичный доступ на уровне консоли.

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

Рассмотрим следующий пример.

Чтобы установить MySQL с помощью Ansible:

- hosts: webservers

  user: vagrant

  sudo: true

  vars_files:

    - vars.yml



  tasks:

    - name: Install MySQL

      action: apt pkg=$item state=installed

      with_items:

        - mysql-server-core-5.5

        - mysql-client-core-5.5

        - libmysqlclient-dev

        - python-mysqldb

        - mysql-server

        - mysql-client



    - name: Start the MySQL service

      action: service name=mysql state=started



    - name: Remove the test database

      mysql_db: name=test state=absent



    - name: Create deploy user for mysql

      mysql_user: user="deploy" host="%" password={{mysql_root_password}} priv=*.*:ALL,GRANT



    - name: Ensure anonymous users are not in the database

      mysql_user: user='' host=$item state=absent

      with_items:

        - 127.0.0.1

        - ::1

        - localhost



    - name: Copy .my.cnf file with root password credentials

      template: src=templates/.my.cnf dest=/etc/mysql/my.cnf owner=root mode=0600



    - name: Update mysql root password for all root accounts

      mysql_user: name=root host={{item}} password={{mysql_root_password}}

      with_items:

        - 127.0.0.1

        - ::1

        - localhost

Как показано выше, мы можем использовать Ansible для установки определенной версии MySQL (5.5), запуска службы, удаления всех тестовых баз данных, добавления пользователя, удаления всех анонимных пользователей, копирования существующего файла my.cnf и обновления пароля root.

Поскольку пароль root MySQL, различная другая конфиденциальная информация (например, версия MySQL) и имя развернутого пользователя MySQL хранятся прямо в конфигурационном файле, безопасность становится насущной проблемой.

Раскрытие конфигурации/файлов

Конфигурация/файлы Docker могут быть идеальной демонстрацией такого рода неправильной конфигурации.

Давайте рассмотрим пример базового официального файла Docker compose (docker-compose.yml), используемого для установки WordPress с MySQL:

version: "3.9"



services:

  db:

    image: mysql:5.7

    volumes:

      - db_data:/var/lib/mysql

    restart: always

    environment:

      MYSQL_ROOT_PASSWORD: somewordpress

      MYSQL_DATABASE: wordpress

      MYSQL_USER: wordpress

      MYSQL_PASSWORD: wordpress



  wordpress:

    depends_on:

      - db

    image: wordpress:latest

    volumes:

      - wordpress_data:/var/www/html

    ports:

      - "8000:80"

    restart: always

    environment:

      WORDPRESS_DB_HOST: db

      WORDPRESS_DB_USER: wordpress

      WORDPRESS_DB_PASSWORD: wordpress

      WORDPRESS_DB_NAME: wordpress

volumes:

  db_data: {}

  wordpress_data: {}

Здесь мы видим, что MySQL 5.7 установлен из последнего образа WordPress, доступного на Docker Hub, а также пароль корня MySQL, имя базы данных, имя пользователя и пароль пользователя.

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

Обнаружение подобных проблем с конфигурацией позволяет blue team предотвратить утечку конфиденциальных данных, которые впоследствии могут быть использованы для осуществления более сложных атак на облачную инфраструктуру.

Раскрытие Kubernetes

Rancher – это мультикластерная платформа оркестровки с открытым исходным кодом, которая позволяет операционным командам развертывать, управлять и обеспечивать безопасность корпоративных Kubernetes.

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

Раскрытие консоли Kubernetes

Консоль Kubernetes (или дашборд) является важной частью настройки Kubernetes.

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

Раскрытие этой консоли может привести к различным типам атак.

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

Раскрытие Kubernetes Kustomization

Инструмент Kubernetes Kustomization используется для настройки объектов Kubernetes с помощью файла “Kustomization”.

Со страницы проектов Kustomize позволяет настраивать необработанные, свободные от шаблонов YAML-файлы для различных целей, оставляя исходный YAML нетронутым и пригодным для использования как есть.

В свою очередь, такая возможность настройки конфигураций делает новые файлы Kustomization довольно мощными, позволяя объединять различные существующие файлы конфигурации Kubernetes.

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

А как насчет уязвимостей программного обеспечения для оркестрации контейнеров?

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

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

Учитывая  уязвимость CVE-2020-16846, затрагивающую SaltStack Salt, программное обеспечение для управления инфраструктурой и оркестровки контейнеров, CVE позволяла осуществлять атаки shell injection при отправке определенных веб-запросов к API SaltStack.

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

Заключение

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

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

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

 



2022-09-09T13:33:57
Закрытие уязвимостей

🐳 Почему процессы в контейнерах Docker не должны запускаться от имени Root

Процессы в контейнере Docker не должны запускаться от имени root.

Безопаснее запускать приложения от имени пользователя, не являющегося root, которое вы указываете в Dockerfile или при использовании docker run.

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

В этой статье вы узнаете об опасностях, связанных с запуском контейнерных приложений от имени root.

Вы также увидите, как создать пользователя, не являющегося root, и настроить namespacing в ситуациях, когда это невозможно.

Почему запуск от имени Root опасен?

По умолчанию контейнеры запускаются от имени root.

Демон Docker запускается от имени root на вашем хосте, и запущенные контейнеры также будут запускаться от имени root.

Хотя может показаться, что root внутри контейнера является независимым пользователем, на самом деле это то же самое, что и учетная запись root на вашем хосте.

Разделение обеспечивается только механизмами изоляции контейнеров Docker.

Нет прочной физической границы; ваш контейнер – это еще один процесс, запущенный пользователем root на ядре вашего хоста.

Это означает, что уязвимость в вашем приложении, среде выполнения Docker или ядре Linux может позволить злоумышленникам выйти из контейнера и выполнить операции с правами root на вашей машине.

Существуют некоторые встроенные средства защиты, которые снижают риск возникновения такой ситуации.

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

Несмотря на эти меры, разрешение запуска приложений от имени root остается опасным.

Так же, как вы ограничиваете использование root в традиционной среде, неразумно без необходимости использовать его в контейнерах.

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

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

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

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

Вы должны создать новую учетную запись пользователя как один из последних этапов в вашем Dockerfile.

Этого можно добиться с помощью инструкции USER:

FROM base-image:latest

RUN apt install demo-package

USER demo-user:demo-group

ENTRYPOINT ["demo-binary"]

Контейнеры, запущенные с этого образа, будут работать под именем demo-user.

Пользователь будет членом группы demo-group.

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

USER demo-user

Вместо имен можно указать идентификатор пользователя (UID) и идентификатор группы (GID):

USER 950:950

Выделение известных UID и GID обычно является самым безопасным способом.

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

USER часто указывается как предпоследняя ступень в Dockerfile.

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

Инструкция apt install в приведенном выше примере имеет законную потребность в root.

Если бы инструкция USER была размещена выше, apt был бы запущен от имени demo-user, который не имел бы необходимых прав.

Поскольку инструкции Dockerfile относятся только к сборкам образов, а не к запущенным контейнерам, безопасно оставить изменение пользователя на более поздний период в Dockerfile.

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

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

COPY initial-config.yaml /data/config.yaml



USER demo-user:demo-group

RUN chown demo-user:demo-group /data

В этом примере каталог /data должен принадлежать demo-user, чтобы приложение могло вносить изменения в свой конфигурационный файл.

Предыдущий оператор COPY скопирует файл от имени root.

Можно воспользоваться сокращенным вариантом, используя флаг –chown вместе с copy:

COPY --chown=demo-user:demo-group initial-config.yaml /data/config.yaml

В этом примере каталог /data должен принадлежать demo-user, чтобы приложение могло вносить изменения в свой конфигурационный файл.

Предыдущий оператор COPY скопирует файл от имени root.

Можно воспользоваться сокращенным вариантом, используя флаг –chown вместе с copy:

$ docker run -d --user demo-user:demo-group demo-image:latest

$ docker run -d --user demo-user demo-image:latest

$ docker run -d --user 950:950 demo-image:latest

Флаг –user запускает процесс контейнера от имени указанного пользователя.

Он менее безопасен, чем инструкция Dockerfile USER, поскольку вам придется применять его отдельно к каждой команде docker run.

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

FROM image-that-runs-as-root:latest

USER demo-user

$ docker build . -t image-that-now-runs-as-non-root:latest

Изменение пользователя стороннего образа может вызвать проблемы: если контейнер ожидает запуска от имени root или нуждается в доступе к путям файловой системы, принадлежащим root, вы увидите ошибки при использовании приложения.

Вы можете попробовать вручную изменить права на пути, вызывающие проблемы.

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

Работа с приложениями, которые должны запускаться от имени root

Разделение имен пользователей – это техника работы с приложениями, которым нужны некоторые привилегии root.

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

Имитированный root в контейнере имеет необходимые привилегии, но вынос не даст root-доступа на хост.

Ремаппинг пространства имен активируется путем добавления поля userns-remap в файл /etc/docker/daemon.json:

{

    "userns-remap": "default"

}

Использование default в качестве значения для userns-remap инструктирует Docker автоматически создать нового пользователя на вашем хосте под именем dockremap.

Root в контейнерах будет отображаться на dockremap на вашем хосте.

При желании можно указать существующего пользователя и группу, используя комбинацию UID/GID или имя пользователя/имя группы:

{

    "userns-remap": "demo-user"

}

Перезапустите демон Docker после применения изменений:

sudo service docker restart

Если вы используете nsuser-remap: default, пользователь dockremap теперь должен существовать на вашем хосте:

id dockremap
uid=140(dockremap) gid=119(dockremap) groups=119(dockremap)

Пользователь также должен появиться в файлах идентификаторов /etc/subuid и /etc/subgid:

$ dockremap:231500:65535

Пользователю выделен диапазон из 65 535 подчиненных идентификаторов, начиная с 231500.

В пространстве имен пользователей идентификатор 231500 сопоставлен с 0, что делает его корневым пользователем в ваших контейнерах.

Будучи UID с высоким номером, 231500 не имеет привилегий на хосте, поэтому атаки на взлом контейнеров не смогут нанести такой большой ущерб.

Все запущенные вами контейнеры будут работать с измененным пространством имен пользователей, если вы не откажетесь от этого с помощью docker run –userns=host.

Механизм работает путем создания каталогов с разнесенными именами внутри /var/lib/docker, которые принадлежат подчиненным UID и GID пользователя с разнесенными именами:

$ sudo ls -l /var/lib/docker/231500.231500



total 14

drwx------ 5 231500 231500 13 Jul 22 19:00 aufs

drwx------ 3 231500 231500 13 Jul 22 19:00 containers

...

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

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

Перед использованием этой опции следует изучить документацию.

Заключение

Запуск контейнерных приложений от имени root представляет собой риск для безопасности.

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

Root в контейнере – это тот же root, что и root на вашем хосте, поэтому успешная компрометация может обеспечить контроль над вашей машиной.

Как автор образа, вы должны включить инструкцию USER в свой Dockerfile, чтобы ваше приложение запускалось без root.

Пользователи образа могут отменить эту инструкцию с помощью docker run –user, чтобы назначить определенные UID и GID. Это поможет смягчить ситуацию, когда образ обычно использует root.

Вы можете еще больше усилить безопасность, удалив все возможности из контейнера с помощью –cap-drop=ALL, а затем включив в белый список те, которые необходимы, с помощью флагов –cap-add.

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

см. также:



2022-08-18T15:00:27
Закрытие уязвимостей