Комментарии 16
Ага, а сколько кода (причем дублируемого) будет в вашем __list_view и __detail_view? А в примере с UserViewSet — это полный код. Осталось только указать queryset и другие атрибуты. Никаких "# Actions here..." там больше нет, всё в миксинах.
> Как видите, особой надобности во ViewSet нету. Трэйс запроса происходит ровно одной строчкой, но нам доступны функции get, post, put и иже с ними.
Что значит надобности? Зависит от решаемой задачи. ViewSet и дженерики хороши в двух случаях: когда всё просто и когда всё сложно.
Когда всё просто — это наследовался от ModelViewSet, указал queryset, serializer_class и endpoint готов.
Когда всё сложно — это ViewSet с различными (в том числе кастомными) миксинами, которые можно применять во всех ViewSet проекта и расширять/изменять их по мере необходимости через методы (типа perform_update у UpdateModelMixin). В итоге имеем правильную и красивую архитектуру приложения без своих костылей.
На счёт Swagger — да, я все эти проблемы побороть не смог. Да что там, даже ApiRoot (тот, который для рендеринга карты урлов на главной) ломается. Но если исследовать проблему чуть глубже — становится понятно, что оно и не может работать. Нужно использовать другой путь, а это обычное дело в разработке.
JS то тут причем? Насколько я пониманию, если взглянуть на стиль вьюсетов внимательнее, то можно найти много общего с принципом SOLID. Тоесть, не нужно придумывать свою соответствующую структуру.
А что до вьюсетов, то они нарушают принцип SOLID где только можно. Начиная с первого: SRP.
По поводу Django-писания, матчасть стоит подтянуть. Я, например, писал об этом в своей статье:
Django-разработчик, помни: все что ты делаешь — это настройка WSGI-приложения.Посмотри документацию о превращении входящего запроса на сервер в исходящий ответ.
Ну а я этим точно не стану заниматься: сроки поджимают.
Ещё хотел бы добавить, что методы класса post/get/put и т.д. создавали красивую экосистему, в которой надстройки в виде actions разумно доставались программисту проекта. ViewSets в эту экосистему слабо вписываются. Тут надо либо их выделять в полноценную концепцию со всеми методами получения и определения, либо удалять нафиг из системы. Полагаю, что так оно скоро и будет. Опенсорсные проекты часто избавляются от непопулярных узлов, либо перерабатывают их концепцию.
DRF — боль моя. То, что для обычного CRUD обычно нужна пачка сериалайзеров — C, R две штуки для U (patch и post) + еще, например, комплект для суперюзера, по-моему автору в голову даже не приходило. 2/3 файла в результате состоит из унылой копипасты.
Отдельная песня — DRF-Swagger (он уже научился догадываться, что на выходе может быть serializer_class[] ?). До удобоваримости пришлось очень сильно дорабатывать кувалдой и какой-то матерью. (input_serializer_class, many=True в yaml и прочее).
Особенно порадовался, как автор в 3.4 (видимо обчитавшись xkcd) ВНЕЗАПНО стал пилить автодокументирование в 15м стандарте (wtf is coreapi?).
А на тему статьи — ViewSets позволяют офигенно наглядно бутстрапить CRUD-образную обвязку любой сущности, выкидывая из CRUD ненужные буквы, и с этой задачей справляются на ура. Че еще от них надо-то?
# http://stackoverflow.com/questions/22616973/django-rest-framework-use-different-serializers-in-the-same-modelviewset
class MultipleSerializerViewSetMixin:
def get_serializer_class(self):
try:
return self.action_serializer_classes[self.action]
except (AttributeError, KeyError):
return super().get_serializer_class()
class MultipleQuerysetViewSetMixin:
def get_queryset(self):
try:
return self.action_querysets[self.action]
except (AttributeError, KeyError):
return super().get_queryset()
Теперь хочу фильтров! Разных! Тут становится понятно, что никакого «get_filters» нам не предоставлено — ну хорошо, переопределим filter_queryset, может даже полностью повторив его код — пускай… И где-то тут и возникает неловкость — как будто тебе дали рог изобилия, но забыли приложить к нему инструкцию и всё, что остаётся — лупить им по стенам и собирать вываливающиеся крошки.
Теперь что касается использования сразу get, post и т.д. Это в большинстве случаев скорее приятно, чем продуктивно. Знание того, что именно заставляет программу работать — оно прекрасно само по себе. Но постоянно переписывать одни и те же строчки для каких-то простых моделек?… Получение данных из request, валидация сериализатора, сохранение — и так 500 раз… А если я хочу в одну транзакцию с сохранением модели включить ещё что-то? Например, запись в журнал об этом изменении? Получается действительно много… даже Много повторяющегося кода. Причём повторяющего зачастую то, что в generic'ах уже кем-то написано, протестировано и упаковано — бери да пользуйся.
Так что по мне вариант — generic'и для сложных моделей, viewset'ы — для простых в две строчки. Есть конечно и свои нюансы — хочешь использовать меньше URL'ов и больше HTTP-методов — всё равно изволь выбирать сериализаторы… Но хотя бы не из простыни на 15 вариантов. Ну а get, post и остальные низкоуровневые методы — это для тех случаев, когда исполняемая логика не укладывается в обычный CRUD.
Не согласен с тем, что методы генериков post/get/put — это низкоуровневое программирование. Скорее, наоборот. REST Framework не надо относить к пространству моделей. Это очевидный функционал формы. Отсюда следует, что отдельная форма — это отдельный класс сериалайзера. А представление, которое разруливает обращение к форме, должно работать с post/get/put а не с create/update/deflorate и т.д. Потому что это вьюха. Она обязана реализовывать функционал HTTP протокола, а не модели/формы для модели.
Deprecated:
YAML docstrings
И работает он теперь через CoreAPI и схемы. DRF предоставляет возможность ручного определения схем. И всё бы ничего, но повторять те же самые поля ещё раз?..
Возможность рисовать схему самому, но при этом таскать описания полей из имеющихся сериализаторов — это был бы не самый лучший, но выход. Можно попробовать покопаться в исходниках — rest_framework.schemas.SchemaGenerator и его get_path_fields, get_serializer_fields, get_pagination_fields и get_filter_fields, возможно, смогут помочь.
В итоге, клиент остался доволен документацией, в документации нет привязки к конкретной технологии, зато все описание выглядит прилично.
Как бонус, можно отдельно задокументировать большую часть ендпоинтов перед началом разработки (с свойствами, доступом и т.п) и дальше пилить серверную часть и клиента независимо друг от друга (сервер покрывался unit + integration тестами, клиент просто мокапил все запросы соответственно документации).
Все время пытался этот способ обойти т.к. боялся проблем из-за расхождения документации и реальности, но как показала практика это не проблема вообще.
Оверинженеринг при документировании ViewSets Django REST Framework