Приветствую, друзья!

Сегодня у меня для вас незапланированная публикация.

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

В результате накопилось большое количество кода, который оказался избыточным, особенно с учётом того, что скоро я планирую перейти к описанию более серьёзного взаимодействия FastAPI с полноценной базой данных (SQLAlchemy с миграциями через Alembic). Поэтому я решил вынести весь код взаимодействия с JSON в отдельную библиотеку.

Так появилась json_db_lite.

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

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

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

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

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

Зачем Нужен JSON

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

JSON (JavaScript Object Notation) — это стандартный текстовый формат для хранения и передачи структурированных данных. Он основан на синтаксисе объекта в JavaScript, но не привязан к этому языку.

Проще говоря, JSON — это основная структура данных, которая используется для общения между приложениями (клиентом и сервером). Благодаря удобной структуре "ключ — значение", JSON используется во всех языках программирования, хотя может называться по-разному. В Python, например, это словари (dict).

Возможности Библиотеки

json_db_lite позволяет:

  • Создавать JSON файл при инициализации класса (можно расценивать как создание базы данных).

  • Добавлять новые записи.

  • Получать все записи.

  • Очищать базу данных.

  • Удалять записи по ключу.

  • Обновлять записи по ключу.

Установка

Библиотека опубликована на PyPi, поэтому вы можете установить её с помощью следующей команды:

pip install --upgrade json_db_lite

Импорт и инициализация

from json_db_lite import JSONDatabase


# Инициализация базы данных
db_client = JSONDatabase('db.json')

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

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

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

def add_data_to_db():
    # массовое добавление
    db_client.add_records([{"id": 1, "name": "Sara"},
                           {"id": 2, "name": "Mark"},
                           {"id": 3, "name": "Charlie"},
                           {"id": 4, "name": "David"}
                           ])
    # добавление одной записи
    db_client.add_records({"id": 5, "name": "Alex"})

Метод принимает словарь или список словарей, добавляя записи в JSON.

Извлечение всех данных

def get_all_data():
    # возвращаем все данные
    return db_client.get_all_records()

Извлечение данных по конкретному ключу

def get_data(key='id', value=4):
    # возвращаем данные по ключу
    return db_client.find_records_by_key(key, value)

Функция возвращает список словарей, даже если возвращается одно значение.

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

def update_data():
    # обновляем данные по ключу у одного словаря
    db_client.update_record_by_key(upd_filter={"id": 4}, new_data=[{"name": "Alex"}, {"age": 31}])

    # обновляем данные по ключу у одного словаря
    db_client.update_record_by_key(upd_filter={"name": "Alex"},
                                   new_data=[{"age": 40}, {"job": "python developer"}])

Метод универсален. В качестве upd_filter передается словарь формата "ключ-значение" для фильтрации. В new_data можно передать список словарей или отдельный словарь. При отсутствии связки "ключ-значение", но при совпадении с фильтром, метод добавит новую связку. Если связка присутствует, то выполнит обновление.

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

def dell_data():
    # удаляем данные по ключу
    db_client.delete_record_by_key(key="name", value="Alex")

После выполнения этого кода будут удалены все словари, у которых name = Alex.

Очистка Базы Данных

def dell_all_data():
    db_client.clear_database()

Заключение

Несмотря на свою простоту, библиотека получилась достаточно гибкой и универсальной. О новостях и обновлениях библиотеки я буду сообщать в своём телеграм-канале «Легкий путь в Python».

Репозиторий проекта на GitHub: JsonDatabase.

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

Благодарю за внимание!

Комментарии (15)


  1. Dair_Targ
    03.07.2024 11:50
    +2

    Как учебное пособие или результат лабы - отлично (только добавьте py.typed!).

    Для реальных задач - отказать:( уж очень много недочётов (например: вычитывает все данные в память, полно fullscan-операций, нет покрытия тестами - test_database.py явно не оно:), нет проверки заявленных версий питона через tox)


    1. yakvenalex Автор
      03.07.2024 11:50

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


  1. kalbas
    03.07.2024 11:50

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


    1. yakvenalex Автор
      03.07.2024 11:50

      А для каких задач подходит чистый модуль JSON? Он с коробки как бы не асинхронный. Хочу обратить внимание. Я вообще не выходил за пределы чистого JSON. Или вы будете утверждать что чистый JSON Python нельзя нигде использовать?


      1. kalbas
        03.07.2024 11:50
        +1

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


        1. yakvenalex Автор
          03.07.2024 11:50

          Понял о чем вы)

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

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

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

          Можно выделить пару дней. Заморочиться. Прописать в коде вообще все что тут вы и прочие комментаторы предложили, чтоб нарваться на очередной хейт. В чем смысл?)

          Сейчас библитоеку стоит расценивать как проба пера - "нужен инструмент" или "не нужен". Лично я для больших парсеров в формате JSON использую MongoDB с библиотекой motor, но а для мелких парсеров и задач по взаимодействию с JSON на Python теперь буду использовать свою библиотеку.

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


          1. kalbas
            03.07.2024 11:50
            +1

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


          1. kalbas
            03.07.2024 11:50
            +1

            Ну и да, вот пожалуйста, чисто питоновская микродокументо-ориентированная база.


    1. ponikrf
      03.07.2024 11:50

      Скажу честно - не совсем понимаю зачем это на питоне. Но в JSе есть такая необходимость. Например есть такая база как NeDB - несмотря на то что она уже давно не разрабатывается, ее продалжают качать и качать. Потому что далеко не всегда нужна база уровня MySql или MongoDB. К сожалению я даже и не знаю сейчас активной библиотеки на JS которая бы развивалась в этом направлении. Последнее чем пользовался - LokiJS. Нужна она была мне для создания локальной базы для сверки с внешней Api подобной базой и выявления разницы между ними.

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


      1. yakvenalex Автор
        03.07.2024 11:50

        Бывают разные задачи в Python и в их рамках часто приходится с JSON взаимодействовать. Как самый яркий пример - это разработка бэкенда для веб-прилождений на Python (FastApi, Flaskи Django). Всё общение по API идет в контексте JSON (как передача, так и обработка данных).

        Ещё, по крайней мере в моей практике, часто приходится работать с готовыми JSON файламы.

        Кроме того. Не зря же JSON встроенная библиотека)


      1. kalbas
        03.07.2024 11:50

        А в чем отличие js от python в данном контексте? Речь же про js-бэкенд?


        1. ponikrf
          03.07.2024 11:50

          Разница в том, что JS может выполнятся на стороне браузера и такие базы работают в том числе и в браузере. JS для таких задач как ложка-вилка)

          Ну если таким пользуются на питоне - ок.


          1. kalbas
            03.07.2024 11:50

            Тогда и речь нужно вести о client-side базах и server-side, вопрос то не в языке. В браузере то у вас всегда есть IndexedDB (наверное я правильно понял что это, я довольно далек от фронта). А на сервере всегда и везде есть sqllite (и не только на сервере кстати), который уже и JSON довольно продолжительное время поддерживает.


  1. YAKOROLEVAZAMKA
    03.07.2024 11:50

    Библиотека предполагает ETL-подход, но для неструктурированных данных кажется проще использовать ELT (Extract - Load - Transform), т.е. сохранить данные as is в какой-нибудь Postgres в поле с типом json, а потом уже обрабатывать это поле

    Т.е. грубо говоря если с помощью библиотеки делаем парсинг json, а потом (как обычно бывает) туда попадают новые ключи \ уходят старые то мы на выходе получим некорректный json. В случае с ELT-подходом просто правим парсер (вместо перезагрузки данных за N-период + так же правки парсера)


  1. Dominux
    03.07.2024 11:50

    Очередная статья от "Опытного Python-разработчика с многолетним стажем" (хотя странно было бы читать статьи по Python от человека, знакомым с ним менее года)

    взаимодействием FastAPI и баз данных

    Простите, что? FastAPI - роутер, а не ОРМ/драйвер к бд. Я даже не стану говорить, что это должны быть разные и абсолютно не знающие друг о друге компоненты системы, но до таких тем видимо ещё далеко

    Допустим, вам нужно парсить большой объем товаров с интернет-магазина

    Как это вообще относится к FastAPI? Я ничего не хочу сказать, но мне кажется, вы действительно несколько лет занимались парсингом и созданием ТГ ботов, а неделю назад узнали о существовании FastAPI и Docker

    В целом, какой смысл писать данную библиотеку на Python и только для Python? Она же будет весьма медленной и прожерливой по памяти. Такие вещи реализуют на языках без рантайм примочек вроде интерпретации и gc, а затем через FFI используют где хотите, в то же самом Python.

    P.s.: очевидный вопрос в стиле "зачем эта либа вообще нужна" задавать не буду, т.к. уже итак все поинтересовались. Может быть всё-таки вернётесь к парсингу инфы с маркетплейсов и ТГ ботам, а не будете продвигать никому не нужный модуль с несколькими CRUD-функциями под видом "классной и универсальной библиотеки". Я понимаю, вы вероятно работали все это время в сфере фриланса и привыкли рекламировать свои решения, какими на самом деле простыми и недалёкими они ни были