2. Содержание
1. Предисловие
2. Django Rest Framework
3. GraphQL
4. Сравнение
a. Роутинг
b. Запросы (front requests)
c. Фильтрация
d. CRUD
e. Права доступа (permissions)
f. Версионность
g. API документация
5. Результат
4. Предисловие. Монолитные страницы
- Монолитные страницы (monolithic style)
Рендеринг на стороне сервера, запросы на перерисовку отдельных частей web-
страниц посредством ajax.
5. Предисловие. REST
- REST
Архитектурный стиль взаимодействия компонентов распределённого приложения в
сети, пользуется популярностью с 2005 г.
Применяется для API, сайтов (SPA) и мобильных приложений.
11. Сравнение. Запросы
Запрос на сущность
1. GET /api/v1/users/
2. GET /api/v1/buildings/
Оптимизация кол-ва запросов:
● Кастомные запросы для получение данных с разных
сущностей.
● Вложенные данные djangorestframework-expander
Единая точка входа
GET /graphql
1. query {
2. allUsers{ ... }
3. allBuildings{ … }
4. }
Оптимизация получения вложенных данных resolve_{method}
select_related и prefetch_related
12. Сравнение. Фильтрация
django-filter
1. class UserView(ListModelMixin, GenericViewSet):
2. serializer_class = UserSerializer
3. queryset = User.objects.all()
4. filter_backends =
(django_filters.rest_framework.DjangoFilterBackend,)
5. filter_fields = “__all__”
6. filter_class = UserCustomFilter
django-filter
1. class UserType(DjangoObjectType):
2. class Meta:
3. model = User
4. interfaces = (relay.Node,)
5. filter_fields = ['id', 'name']
6. class Query(ObjectType):
all_users = DjangoFilterConnectionField(UserType,
filterset_class=UserCustomFilter)
13. Сравнение. Фильтрация
django-filter
1. GET /api/v1/users/?category=1
2. GET /api/v1/users/?search=oleg
3. GET /api/v1/users/?search=oleg
4. GET /api/v1/users/?username__contains=oleg
django-filter
1. query{
2. allUsers(category: "QnVpbGRpbmdUeXBlOjE="){ ... }
3. allUsers(name: "oleg"){ ... }
4. allUsers(name_Icontains: "oleg"){ ... }
5. }
14. Сравнение. CRUD
Serializers
1. class BuildingView(RetrieveModelMixin, UpdateModelMixin,
DestroyModelMixin, ListModelMixin, CreateModelMixin,
GenericViewSet):
2. serializer_class = BuildingSerializer
Mutations
Установка пакета с доп. функциями
pip install graphene-django-extras
1. class BuildingSerializerMutation(DjangoSerializerMutation):
2. class Meta:
3. serializer_class = BuildingSerializer
16. Сравнение. CRUD
Serializers
Создание building
POST /api/v1/building/
1. {
2. "address": "test",
3. "name": "test",
4. }
Mutations
Создание building
1. mutation{
2. buildingCreate(newBuilding:{name: "test", address: "test
address"}){
3. building {
4. id
5. name
6. }
7. }
8. }
17. Сравнение. CRUD
Serializers
Изменение building
PATCH | PUT /api/v1/building/{id}/
1. {
2. "address": "string",
3. "name": "string",
4. }
Mutations
Изменение building
1. mutation{
2. buildingUpdate(newBuilding: {id: "4", name: "new name"}){
3. building{
4. id
5. name
6. }
7. ok
8. errors{
9. field
10. messages
11. }
12. }
13. }
18. Сравнение. CRUD
Serializers
REST запросы для CRUD оперций
1. DELETE /api/v1/building/{id}/
Mutations
Удвление building
1. mutation{
2. buildingDelete(id: "3"){
3. building {
4. id
5. name
6. }
7. }
8. }
19. Сравнение. Права доступа
Ограничение прав на уровне Request
1. class BuildingView(RetrieveModelMixin,
CreateModelMixin, GenericViewSet):
2. queryset = Building.objects.all()
3. permission_classes = (IsAuthenticated,
IsOwnerOrReadOnly)
Установка пакета
pip install graphene-permissions
1. class BuildingType(AuthNode, DjangoObjectType):
2. permission_classes = (AllowAuthenticated,)
3. class Meta:
4. model = Building
5. interfaces = (relay.Node,)
20. Сравнение. Права доступа
Кастомные права
1. class IsOwnerOrReadOnly(permissions.BasePermission):
2. """
3. Object-level permission to only allow owners of an object to
edit it.
4. """
5. def has_object_permission(self, request, view, obj):
6. if request.method in permissions.SAFE_METHODS:
7. return True
8. return obj == request.owner
1. class AuthNode:
2. permission_classes = (AllowAny, )
3. @classmethod
4. def get_node(cls, id, context, info):
5. def has_permission():
6. return all([perm() for perm in
cls.permission_classes])
7. if has_permission():
8. try:
9. object_instance =
cls._meta.model.objects.get(id=id)
10. except cls._meta.model.DoesNotExist:
11. object_instance = None
12. return object_instance
21. Сравнение. Права доступа
Пример запрета на все запросы
1. class DenyAny:
2. """
3. Deny for all permission
4. """
5. def has_node_permission(self, info, id):
6. return False
7. def has_mutation_permission(self, input, context, info):
8. return False
9. def has_filter_permission(self, context):
10. return False
1. class AuthNode:
2. permission_classes = (AllowAny, )
3. @classmethod
4. def get_node(cls, info, id):
5. def has_permission():
6. return all([perm().has_node_permission(info, id) for
perm in cls.permission_classes])
7. if has_permission():
8. try:
9. object_instance =
cls._meta.model.objects.get(id=id)
10. except cls._meta.model.DoesNotExist:
11. object_instance = None
12. return object_instance
13. else:
14. raise PermissionDenied(PERMISSION_DENIED_MSG)
22. Сравнение. Права доступа
Подключение
1. class BuildingType(AuthNode, DjangoObjectType):
2. permission_classes = (DenyAny,)
3. class Meta:
4. model = Building
5. interfaces = (relay.Node,)
6. filter_fields = ['id', 'name']
23. Сравнение. Версионность
Роутинг
1. GET /api/v1/users/
2. GET /api/v2/users/
3. POST /api/v1/buildings/
4. POST /api/v2/buildings/
Подключение в url.py
1. urlpatterns = [
2. url(r'^api/v1/', include('users.urls_v1')),
3. url(r'^api/v2/', include('users.urls_v2')),
4. ]
Пример с мутациями
1. class Mutations(ObjectType):
2. building_create =
BuildingSerializerMutation.CreateField(deprecation_reason
='Some one deprecation message')
25. Результат
DRF GraphQL
Роутинг Нужно описывать роуты один роут на все запросы
Запросы Несколько запросов, Кастомные роуты. Экспанды для
вложенных данных
Один запрос на получение нужных данных
Фильтрация django-filter django-filter
CRUD Mixins и Serializers Mutation и Serializers
Права доступа Есть удобное управление Пакет не заработал, правил классы
Версионность Добавление новых роутов Описание устаревших переменных в документации
API документация Swagger
Вся документация для работы с django
Graphiql
Нет с коробки crud операций, permissions