Comments 34
Зачем Вы указываете кодировку utf8 в заголовке файла? Проект же под третий питон?
Да, проект написан под 3ку. Относительно наличия «utf8» в заголовке каждого файла могу лишь сказать что это банальная привычка. На работе (наверное, как и многие) все также пишу на 2ой ветке.
Точнее, это можно делать пока у вас количество пользователей не больше десятка-двух.
Потом всё начнёт залипать.
Были идеи сделать что-то в связке с aiopg, чтобы появилась возможность работы асинхронно с БД (хоть только и PostgreSQL). Правда возникает вполне простой вопрос: а как мне можно перейти в асинхронный код при работе aiorest-ws с Django, у которого множества различных адаптеров есть под разные базы?
Текущее решение не идеально, на текущий момент, но хоть есть от чего отталкиваться :)
Нельзя быть немного беременной, а потом надеяться как-то продумать ситуацию более детально.
Код или синхронный или — а\синхронный. Совмещать не удасться.
Справедливости ради, если всё остальное в норме, то можно сказать, что работа с БД просто ещё не реализована правильно… и этот частный, хоть и частый случай, по-моему можно таки продумать более детально чуть позже (естественно, до того как предлагать применять в продакшене).
Вероятно, у вас знакомство с asyncio исключительно теоретическое.
Чтобы переделать на корутины нужно менять сигнатуры кучи методов как минимум.
Получается новая библиотека, несовместимая со старой.
Вы абсолютно правы, я знаком с asyncio, да и с остальными async инструментами, сугубо теоретически, причём именно из-за озвученной вами проблемы — нужно всё переписать чтобы сделать что-то маломальски пользователе-ориентированное. Раз вы говорите, что всё так плохо, то, видимо, автору нужно приоритезировать решение этой проблемы.
Просто так вызывать блокирующий синхронный код нельзя — event loop залипает.
Запускать в thread pool — ненамного лучше. Под нагрузкой производительность начинает заметно проседать.
Остается два выхода:
- Писать свои правильные асинхронные библиотеки
- Поднять руку, резко её опустить и сказать: "И зачем мне эта асинхра? Буду до пенсии писать на Django!".
Первый вариант интересный и познавательный, второй — спокойный и стабильный.
В случае же с БД обойтись без Django вообще почти не вариант. Там и админка, и генерация/применение/откат миграций, и удобный отлаженный ORM. На перенос всего этого хозяйства в асинхронный компонент уйдут годы. В промежуточный же этап в большинстве случаев придется поддерживать дублирование кода (например, описывать модели нужно будет в обоих компонентах).
Не думаю что это рабочее решение. С таким же успехом можно мастерить асинхронный Python код который для доступа к базе дергает Go или JavaScript. Меня от этой идеи в дрожь бросает (и не потому что я Go/JavaScript недолюбливаю).
- Django — не ко всем бочкам затычка. И эта затычка очень часто оказывается не той формы как дырка. Как ORM она ужасна.
А Django-затычка как раз чаще именно той формы, что и дырка — это мое мнение :) В конце концов всегда можно расширить/допилить недостающий функционал, архитектура Django это позволяет.
Насчет ORM, по большому счету все они ужасны. Я думаю, что идея ORM не в том, чтобы предоставлять более удобный способ выполнять SQL запросы, а в том, чтобы объединить под одной общей абстракцией такие вещи как: описание модели, генерация/применение/откат миграций и осуществление самих запросов. Сложно представить решение, которое все перечисленное реализует при помощи нативного SQL — поддержание консистентного состояния системы в этом случае будет задачей очень сложной.
В итоге остановился на такой реализации, в доке к websockets описана, псевдокод:
async def receive():
""" Слушаем сокет """
async def message_to_sent():
""" Ждем сообщение для отправки """
While True:
listener_task = asyncio.ensure_future(receive())
sender_task = asyncio.ensure_future(message_to_sent())
done, pending = await asyncio.wait(
[listener_task, sender_task], return_when=asyncio.FIRST_COMPLETED)
if listener_task in done:
# Процессинг входящих сообщений
handler(listener_task.result())
else:
listener_task.cancel()
if sender_task in done:
# Отправка
send_str(sender_task.result())
else:
sender_task.cancel()
Или это можно сделать более «красиво»?
4) Здорово, теперь кое что прояснилось.
И после этого читать не получается. )
Потому что не прояснилось и потому что тяжело и лениво вникать.
Для кого и для чего материал?
Если это тутор, то на какой уровень подготовки?
Если это описание фреймворка, то слишком абстрактный пример и много «воды».
Если это подход к построению фреймворка, то слишком много ненужных в этом случае деталей…
Браво! Я просто не могу подобрать слов! Тема WebSockets в Python для меня была просто пыткой, сколько я ни пытался заставить себя погрузиться в неё, всё время какое-то отторжение происходило и я быстро находил на что отвлечься. aiorest-ws (по крайней мере по примерам и описанию) — это огромный шаг в сторону упрощения.
Ваша реализация в стиле Flask мне импонирует, как и использование REST подхода. Swagger (OpenAPI) вам не факт, что поможет в плане какой-то готовой реализации (по крайней мере я не слышал о REST WebSockets поддержке ни в Swagger-UI, ни в Swagger-Codegen), но для HTTP RESTful API он просто божесвеннен, на мой взгляд, и я даже собрал демо на Flask-RESTplus (фреймворк для HTTP REST Swagger API) для более-менее жизненного примера, может что-то интересное для себя и в нём найдёте.
Кстати, а ваш роутинг можно на модули разбивать, например, как Blueprint в Flask? Это гораздо удобнее, на мой взгляд, чем один общий router
где-то там в корне проекта.
Я вижу, что ваши сериализаторы очень похожи на Marshmallow, но почему бы просто не взять сам Marshmallow вместо нового велосипеда? Неужели требование к минимальности зависимостей настолько строгое?
Браво! Я просто не могу подобрать слов! Тема WebSockets в Python для меня была просто пыткой, сколько я ни пытался заставить себя погрузиться в неё, всё время какое-то отторжение происходило и я быстро находил на что отвлечься. aiorest-ws (по крайней мере по примерам и описанию) — это огромный шаг в сторону упрощения.
Я бы сказал немного попроще – эксперимент. На текущий момент времени чего-то готового и работающего из коробки с веб-сокетами, в привычном стиле я так и не нашел (да и сейчас, вроде как ситуация не особо поменялась). Да, есть что-то вроде расширений (или плагинов) для того же Django REST, но немного не то, чего я ожидал бы увидеть.
Вполне возможно, что существуют какие-то «закрытые» реализации подобных библиотек, которые имеют что-то схожее с тем, что я постарался описать, но не является open source. А жаль.
Ваша реализация в стиле Flask мне импонирует, как и использование REST подхода. Swagger (OpenAPI) вам не факт, что поможет в плане какой-то готовой реализации (по крайней мере я не слышал о REST WebSockets поддержке ни в Swagger-UI, ни в Swagger-Codegen), но для HTTP RESTful API он просто божесвеннен, на мой взгляд, и я даже собрал демо на Flask-RESTplus (фреймворк для HTTP REST Swagger API) для более-менее жизненного примера, может что-то интересное для себя и в нём найдёте.
Какого-то конкретного решения о структуре проекта (вроде тех, что предлагаются в Django или Flask) я не описывал. Пока просто выбирайте тот стиль что удобнее будет вам.
Спасибо за ссылку, посмотрю на досуге. Вдруг чего-нибудь возьму на вооружение.
Кстати, а ваш роутинг можно на модули разбивать, например, как Blueprint в Flask? Это гораздо удобнее, на мой взгляд, чем один общий router где-то там в корне проекта.
В реализации класса SimpleRouter есть метод include, который принимает другой роутер в качестве параметра. Внутри нее просто копируются роуты из одного в другой. То есть конечный роутер будет иметь пути нескольких роутеров: свой, и те, что мы включили через вызов include.
Я вижу, что ваши сериализаторы очень похожи на Marshmallow, но почему бы просто не взять сам Marshmallow вместо нового велосипеда? Неужели требование к минимальности зависимостей настолько строгое?
Лишние трудности закаляют (надо же было себе какой-то челенж придумать), да и сделать что-то свое всегда интересно. Исходники библиотеки Marshmallow во многом хорошо подсказывали как решать ту или иную задачу при сериализации классов SQLAlchemy.
REST WebSockets
Это оксюморон.
При обсуждении непосредственно и возникла идея, что было бы классно иметь достаточно «гибкий» фреймворк, который использует веб-сокеты, через которые данные циркулируют в обе стороны.
Все же почему вебсокеты?
Простите, но я не могу не оставить это видео здесь.
Есть aiopg который позволяет использовать query-builder алхимии, и никто не пытается примостить ORM алхимии до кучи к нему. Во первых — это не особо кому-то и нужно, во-вторых — это совсем не тривиальная задача.
В общем случае, я бы на твоём месте прикрутил поддержку aiopg, переписал все твои вьюхи чтобы они сериализовали/десериалзовали объекты. Всю работу с БД (чтение, запись и т.д.) вынес бы в отдельные методы (корутины) которые надо было бы реализовывать пользователю библиотеки.
Сказ о том как я свой REST фреймворк с веб-сокетами писал