Обзор
Рано или поздно каждый веб -проект испытывает необходимость для сложной фильтрации. Социальное приложение не имеет смысла без поиска по соединениям. Хорошая платформа автоматизации снабжения должна фильтровать заказы по продуктам или рынкам. Любой интернет -магазин в 2020 году позволяет вам фильтровать товары по разным категориям … Я мог бы продолжить этот список навсегда, но я надеюсь, что эта идея довольно ясна. Однако открытый вопрос заключается в том, насколько сложна должна быть эта фильтрация и что нужно для ее реализации.
Фильтрация 🌪 кажется таким естественным в настоящее время, поэтому считается, что каждая зрелая структура, такая как Django Rest Framework Имеет все инструменты, которые вам нужны. DRF действительно предоставляет широкий спектр библиотек, которые охватывают большинство общих технических сценариев. Когда вы выпустите модель MVP и домена проекта довольно проста, некоторые библиотеки, такие как Django-Filter Может показаться серебряной пулей. Но по мере того, как проект становится все больше, API расширяется, а модель домена становится все более и более сложной. Довольно скоро можно узнать, что существующие инструменты не охватывают все ваши сценарии бизнеса и должны быть заменены чем -то более мощным. Вот где Django-rql Вступает в игру!
Чтобы понять истинную рассуждение для создания еще большее библиотека , Я хочу упомянуть об этом в CloudBlue Connect Мы подходим к фильтрации как важную Бизнес особенность. Как любая другая функция продукта, все начинается с требований. И вот они:
- Фильтры должны быть читаемыми человеком (двойные подчеркивания хорошо!) ;
- Существует множество деловых случаев, когда или нет или нет логических операторов (даже при гнездовании) или внедорожных операций списка, поэтому они должны быть изначально поддерживаться рамками;
- Конфигурация фильтра должна быть декларативной (меньше кода лучше!);
- Но есть много случаев, когда логика фильтра не отображает структуру DB (ORM), и эти случаи должны быть одинаково поддерживаются;
- Connect находится на пути стать членом Инициатива OpenAPI , что означает, что структура должна поддерживать автоматическую документацию в формате OpenAPI 3.0;
- Фильтрация должна быть действительно тщательно протестирована;
- Должен быть способ повлиять на представление API объектов (нам нужно поддерживать включение/исключение полей посредством параметров запроса).
Django-rql был создан с опытом использования других удивительных библиотек фильтрации для покрытия всех этих требований. В этой статье я быстро опишу, как именно рамки достигают этого, и как кто -либо может использовать его в своих проектах, чтобы сделать потрясающие API REST.
Мы использовали эту библиотеку в производстве в нескольких услугах уже более года. Он хорошо протестирован (имеет 100% покрытие), быстро, легко настроен и имеет множество отличных функций. Чтобы узнать больше, пожалуйста, обратитесь к нашему Документация сообщества или на видео ниже.
Человеческие читаемые фильтры
Двойная подчеркивая нотация – это первый класс гражданин в мире Джанго: он используется повсюду для поиска поля и отношений. Большинство библиотек для фильтрации в Django или DRF используют одну и ту же обозначения для фильтрации в параметрах запроса. Чтобы проиллюстрировать дело, давайте представим следующую доменную модель: Компания владеет несколькими продуктами с разными категориями . Клиенты нашей службы просят нас разоблачить компании Json REST API с возможностью фильтрации компаний по имени и по категориям их продуктов. Строка запроса может выглядеть как:
/companies?products__category__id__in=CAT1-ID,CAT2=ID&name__startswith=Clou
В этом подходе есть несколько проблем:
- В мире JavaScript, откуда приходит JSON, DOT обозначения используется для ссылки на вложенные объекты. Плюс, в целом, DOT является гораздо более широким используемым типом сепаратора.
- Операторы, как в или StartSwith становятся частью свойств, и становится трудно отличить отфильтрованное свойство от типа операции.
- Не совсем ясно, если
Cat2 = id
является отдельной операцией или является значением предыдущего сравнения (кронштейны не могут быть использованы).
В нотации RQL предыдущий запрос может выглядеть как:
/companies?in(products.category.id,(CAT1-ID,"CAT2=ID"))&like(name,Clou*)
Этот запрос избавляется от всех недостатков предыдущего подхода: точки используются вместо подчеркивания, операторы и значения визуально различимы. Но, честно говоря, в и как Операторы RQL могут показаться вам незнакомыми. Таким образом, я думаю, это подходящее время, чтобы описать, что означает аббревиатура «RQL».
RQL (язык запросов ресурсов) предназначен для современной разработки приложений. Он построен для Интернета, готов к NOSQL и очень расширяется с помощью простого синтаксиса. Это язык запросов для быстрого и удобного взаимодействия с базой данных. RQL был разработан для использования в URL-адресах для запроса структур данных в объектном стиле.
Я не хочу глубоко погружаться в описание языка, так как использование из следующих разделов будет показывать практически все, что вам нужно знать об этом простом языке. Но если вы готовы узнать больше о RQL, вот хорошая ссылка для вас:
https://www.sitepen.com/blog/resource-query-language-a-query-language-for-the-web-nosql/
Поддерживаемые операторы
В предыдущем абзаце мы уже видели два основных оператора RQL: в и как Анкет Django-rql поддерживает гораздо более широкое количество операторов:
- Сравнение (EQ, NE, GT, GE, LT, LE, Like, Ilike, Search)
/companies?name=Company≥(created.at,2019-02-12)&products.id=ne=PRODUCT-ID
Давайте отдельно посмотрим на части этого запроса. Имя = Компания
это синтаксический сахар над EQ (имя, компания)
операция Поскольку точное сравнение равенства является наиболее широко используемой операцией, был создан специальный синтаксис для удобства использования. ge (created.at, 2019-02-12)
может быть переведен как «Компания Компания создана больше или равна (позже), чем 12 февраля 2019 г. ». Последнее выражение Продукция.id = ne = product-id
является псевдонимом для следующей операции ne (products.id, product-id)
, который может быть переведен как ” Компания, которая не имеет продуктов идентификации продукта “. Синтаксис из последнего выражения может использоваться, если вы не ожидаете, что у вас будут много сложных операций или просто, если вам это нравится больше. Я бы предложил только не смешивать разные стили в одном и том же выражении запроса, поскольку его становится труднее читать его.
Давайте также рассмотрим сценарий, где мы хотим искать по названию компании, но мы только помним, что он имеет «громкий» внутри. В этом случае у нас есть следующие варианты:
/companies?like(name,*loud*) /companies?ilike(name,ClOuD*) /companies?search=loUd
Если бы у нас была компания, названная CloudBlue Connect В нашей службе каждый из вышеперечисленных запросов вернет его нам в ответ. как Позволяет нам искать определенное поле с помощью схемы предоставленного значения ( *
равняется любому символу). ilike это нечувствительная версия оператора. Поиск Оператор псевдонимов в Или ilike фильтрация всеми фильтрами, которые поддерживают такие поиски.
Важно понимать, что каждый поддерживаемый фильтр имеет определенный тип. Поддерживаемые поиски вычисляются автоматически с помощью Django-RQL, на основе этого типа. Например, название компании может быть объявлено как не нулевое Charfield в модели Django. По умолчанию следующие операторы будут поддерживаться для фильтра имени: EQ, NE, как, ilike. Но вы всегда можете переопределить все, единственные реальные ограничения – это возможности выбранного двигателя БД.
- Список (in, out)
/companies?in(id,(COMPANY-ID1,COMPANY-ID2))
Во многих случаях пользовательского интерфейса необходимо запросить данные из одной коллекции, а затем извлечь связанные данные из другой в массовой операции. Вот где в Оператор пригодится. вне просто эквивалент не в Анкет
- Логично (и, или нет)
/companies?not(name=default)&(products.id=PRD-ID1|like(name=def*))
Вот где Django-rql начинает показывать, что это настоящая сила! Или является первоклассным гражданином в мире RQL, который не является распространенным случаем для большинства рамок фильтрации DRF. Кроме того, запросы RQL поддерживают глубокое логическое гнездование, которое может быть дорогостоящим для вашего двигателя DB, но является отличной особенностью для ваших потребителей API.
Во всяком случае, давайте проанализируем вышеупомянутый запрос. На естественном языке это звучит как ” Дайте мне компании, у которых нет имени по умолчанию и у которого есть продукт PRD-ID1 или иметь имя, начиная с DEF “. Довольно мощно, не так ли? Более того, в RQL есть несколько обозначений для И и Или Операторы, и вы можете выбрать любой, что вам нравится больше. И операции могут иметь следующую структуру: expr & expr & ...
или expr, expr, ...
или и (expr, expr, ...)
; пока или: (expr | expr | ...)
или (expr; expr; ...)
или или (expr, expr, ...)
. Не Имеет единственную нотация, и использование ясно свыше запроса.
- Константы (null (), empty ())
/companies?name=ne=empty()&products.id=null()
Выше постоянные помогают, когда это необходимо для фильтрации пустой строкой или проверить, существует ли определенное поле/отношение. Обе эти константы могут использоваться в операциях списка, которые могут облегчить использование фильтров в пользовательском интерфейсе.
- Заказа
/companies?ordering(-name,+products.name)
Заказ является важной функцией хорошей коллекции API. Django Rest Framework предлагает Чтобы явно указать поля, впадится, какой заказ может быть сделан, и это отличная идея, поскольку заказ может быть супер дорогостоящей операцией для вас, БД. Проблема в том, что DRF частично ломает СУХОЙ Принцип, так как нам нужно объявить некоторые фильтры дважды (или даже трижды, если мы также указываем поля поиска). И если имена поля ORM не сопоставляются с именами API, ситуация становится еще хуже, так как вам нужно дублировать отображения. Django-rql Решает все эти проблемы с декларативными конфигурациями, которые позволяют явно указывать для каждого поля, если его можно заказать или искать.
- Выбирать
/companies?select(+owners,-products)
Если вы прочитали до этого момента, то вы уже знаете, что Django-rql это довольно мощный инструмент, который может быть полезен для вашего проекта. Но Реальная сила 💪 🏽 Эта структура находится в избранной функциональности, которая позволяет включать/исключать набор полей с оптимизацией запросов SQL одновременно! Пожалуйста, прочитайте выделенный абзац ниже, чтобы понять, как он работает и почему он может сэкономить вам много денег и вычислительного времени DB в долгосрочной перспективе.
Сила избранного
Выберите Оператор позволяет динамически влиять на представление API объекта через фильтры в строке запроса. Есть несколько библиотек DRF, которые обеспечивают аналогичную базовую функциональность, но Django-rql Выходит за рамки простой фильтрации результатов. Framework позволяет вам объявлять конфигурации, что даже SQL -запросы оптимизируются автоматически! Некоторые коллекции могут полагаться на миллионы записей в БД и в таких случаях, Выберите становится фреймворком Убийственная особенность . Давайте посмотрим на это в действии ( Если вы хотите попробовать самостоятельно, я создал django_rql_select_example Репозиторий специально для вас ). Допустим, мы хотим создать API продуктов REST, на основе DRF и Django-rql . Начнем с создания следующих моделей:
Мы также создаем сериализаторы DRF для нашего API:
И мы описываем наш Декларативная конфигурация Для фильтров RQL:
Мы настраиваем настройки, представления, URL -адреса, запускаем миграции, загрузку светильники и наконец запустить сервер. Давайте уже сделаем несколько запросов!
curl -s "127.0.0.1:8000/api/products/" | jq '. | length'
Посмотрим, что есть 3 Предметы в коллекции. Давайте добавим фильтр и получим все продукты, которые начинаются с «Connect».
curl -s "127.0.0.1:8000/api/products/?like(name,Connect*)" | jq '.'
Вы увидите следующий результат ( связанный SQL ):
[ { "id": 1, "name": "Connect", "category": { "id": 1, "name": "Cloud Applications" } }, { "id": 2, "name": "Connect Zapier Extension", "category": { "id": 1, "name": "Cloud Applications" } } ]
Если мы хотим включить Компания каждого Товар В ответ мы сделаем следующий запрос:
curl -s "127.0.0.1:8000/api/products/?like(name,Connect*)&select(company)" | jq '.'
И мы получаем ожидаемый результат ( связанный SQL ):
[ { "id": 1, "name": "Connect", "category": { "id": 1, "name": "Cloud Applications" }, "company": { "id": 1, "name": "CloudBlue Connect" } }, { "id": 2, "name": "Connect Zapier Extension", "category": { "id": 1, "name": "Cloud Applications" }, "company": { "id": 1, "name": "CloudBlue Connect" } } ]
Для получения дополнительных примеров, пожалуйста, обратитесь к библиотеке Тесты или в при условии демонстрации Анкет
Поддержка OpenAPI 3.0
Одна из ключевых особенностей Django-rql является поддержкой автоматической генерации спецификации OpenAPI. Пример автоматически сгенерированной спецификации можно увидеть в разделе API REST CloudBlue Connect Community Portal Анкет Автоматизация-это здорово, но написанные человеком объяснения часто приносят огромную ценность для клиентов, поэтому структура позволяет простой настройку любого фильтра через Openapi Раздел в декларативной конфигурации. Пример настройки:
{ 'filter': 'published.at', 'openapi': { 'required': True, 'deprecated': True, 'description': 'Good description', 'hidden': False, 'type': 'string', 'format': 'date', } }
Резюме
Это уже довольно длинная статья, и я думаю, что это идеальное время, чтобы сделать короткое резюме. Если вы ищете мощное простое в использовании решение API-фильтрации для вашего проекта Django, я настоятельно рекомендую попробовать Django-rql Анкет Вы можете легко установить его из PYPI (поддерживается Python 3.6+) и начать использовать за считанные минуты:
pip install django-rql
Спасибо за ваше время!
Если у вас есть какие -либо деловые или технические вопросы и предложения, давайте обсудим их здесь, в GitHub или 🤙 в LinkedIn .
Оригинал: “https://dev.to/maxipavlovic/powerful-filtering-for-django-rest-framework-2g8j”