From 2e17d7265d2d071926b853da7fa5daf329622d38 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Wed, 20 Nov 2019 16:29:46 +0300 Subject: [PATCH 1/2] add back api for collection --- apps/collection/serializers/back.py | 61 ++++++++++++++++++++++++++++- apps/collection/urls/back.py | 9 ++--- apps/collection/views/back.py | 54 +++++++++++++++++++------ apps/utils/views.py | 28 +++++++++++++ 4 files changed, 133 insertions(+), 19 deletions(-) diff --git a/apps/collection/serializers/back.py b/apps/collection/serializers/back.py index 4cc76b2f..bb88a778 100644 --- a/apps/collection/serializers/back.py +++ b/apps/collection/serializers/back.py @@ -1,8 +1,14 @@ from rest_framework import serializers + +from collection import models +from collection.serializers.common import CollectionBaseSerializer +from establishment.models import Establishment from location.models import Country from location.serializers import CountrySimpleSerializer -from collection.serializers.common import CollectionBaseSerializer -from collection import models +from product.models import Product +from utils.exceptions import ( + BindingObjectNotFound, RemovedBindingObjectNotFound, ObjectAlreadyAdded +) class CollectionBackOfficeSerializer(CollectionBaseSerializer): @@ -31,3 +37,54 @@ class CollectionBackOfficeSerializer(CollectionBaseSerializer): 'start', 'end', ] + + +class CollectionBindObjectSerializer(serializers.Serializer): + """Serializer for binding collection and objects""" + + ESTABLISHMENT = 'establishment' + PRODUCT = 'product' + + TYPE_CHOICES = ( + (ESTABLISHMENT, 'Establishment'), + (PRODUCT, 'Product'), + ) + + type = serializers.ChoiceField(TYPE_CHOICES) + object_id = serializers.IntegerField() + + def validate(self, attrs): + view = self.context.get('view') + request = self.context.get('request') + + obj_type = attrs.get('type') + obj_id = attrs.get('object_id') + + collection = view.get_object() + attrs['collection'] = collection + + if obj_type == self.ESTABLISHMENT: + establishment = Establishment.objects.filter(pk=obj_id).\ + first() + if not establishment: + raise BindingObjectNotFound() + if request.method == 'POST' and collection.establishments.\ + filter(pk=establishment.pk).exists(): + raise ObjectAlreadyAdded() + if request.method == 'DELETE' and not collection.\ + establishments.filter(pk=establishment.pk).\ + exists(): + raise RemovedBindingObjectNotFound() + attrs['related_object'] = establishment + elif obj_type == self.PRODUCT: + product = Product.objects.filter(pk=obj_id).first() + if not product: + raise BindingObjectNotFound() + if request.method == 'POST' and collection.products.\ + filter(pk=product.pk).exists(): + raise ObjectAlreadyAdded() + if request.method == 'DELETE' and not collection.products.\ + filter(pk=product.pk).exists(): + raise RemovedBindingObjectNotFound() + attrs['related_object'] = product + return attrs diff --git a/apps/collection/urls/back.py b/apps/collection/urls/back.py index eee40327..6a6dbd54 100644 --- a/apps/collection/urls/back.py +++ b/apps/collection/urls/back.py @@ -1,11 +1,10 @@ """Collection common urlpaths.""" -from django.urls import path +from rest_framework.routers import SimpleRouter from collection.views import back as views app_name = 'collection' +router = SimpleRouter() +router.register(r'', views.CollectionBackOfficeViewSet) -urlpatterns = [ - path('', views.CollectionListCreateView.as_view(), name='list-create'), - path('/', views.CollectionRUDView.as_view(), name='rud-collection'), -] +urlpatterns = router.urls diff --git a/apps/collection/views/back.py b/apps/collection/views/back.py index 78a2dcb0..a989ec56 100644 --- a/apps/collection/views/back.py +++ b/apps/collection/views/back.py @@ -1,19 +1,49 @@ -from rest_framework import generics, permissions +from rest_framework import permissions +from rest_framework import viewsets, mixins + from collection import models -from collection.serializers import back +from collection.serializers import back as serializers +from utils.views import BindObjectMixin -class CollectionListCreateView(generics.ListCreateAPIView): - """Collection list-create view.""" +class CollectionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): + """ViewSet for Collection model.""" + + pagination_class = None + permission_classes = (permissions.AllowAny,) queryset = models.Collection.objects.all() - serializer_class = back.CollectionBackOfficeSerializer - # todo: conf. permissions by TT - permission_classes = (permissions.IsAuthenticated, ) + serializer_class = serializers.CollectionBackOfficeSerializer -class CollectionRUDView(generics.RetrieveUpdateDestroyAPIView): - """Collection list-create view.""" +class CollectionBackOfficeViewSet(mixins.CreateModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + mixins.RetrieveModelMixin, + BindObjectMixin, + CollectionViewSet): + """ViewSet for Collection model for BackOffice users.""" + + permission_classes = (permissions.IsAuthenticated,) queryset = models.Collection.objects.all() - serializer_class = back.CollectionBackOfficeSerializer - # todo: conf. permissions by TT - permission_classes = (permissions.IsAuthenticated, ) + serializer_class = serializers.CollectionBackOfficeSerializer + bind_object_serializer_class = serializers.CollectionBindObjectSerializer + + def perform_binding(self, serializer): + data = serializer.validated_data + collection = data.pop('collection') + obj_type = data.get('type') + related_object = data.get('related_object') + if obj_type == self.bind_object_serializer_class.ESTABLISHMENT: + collection.establishments.add(related_object) + elif obj_type == self.bind_object_serializer_class.PRODUCT: + collection.products.add(related_object) + + def perform_unbinding(self, serializer): + data = serializer.validated_data + collection = data.pop('collection') + obj_type = data.get('type') + related_object = data.get('related_object') + if obj_type == self.bind_object_serializer_class.ESTABLISHMENT: + collection.establishments.remove(related_object) + elif obj_type == self.bind_object_serializer_class.PRODUCT: + collection.products.remove(related_object) diff --git a/apps/utils/views.py b/apps/utils/views.py index d3d09079..870e132f 100644 --- a/apps/utils/views.py +++ b/apps/utils/views.py @@ -4,6 +4,7 @@ from django.conf import settings from django.db.transaction import on_commit from rest_framework import generics from rest_framework import status +from rest_framework.decorators import action from rest_framework.response import Response from gallery.tasks import delete_image @@ -121,3 +122,30 @@ class CreateDestroyGalleryViewMixin(generics.CreateAPIView, # Delete an instances of Gallery model gallery_obj.delete() return Response(status=status.HTTP_204_NO_CONTENT) + + +# BackOffice user`s views & viewsets +class BindObjectMixin: + """Bind object mixin.""" + + def get_serializer_class(self): + if self.action == 'bind_object': + return self.bind_object_serializer_class + return self.serializer_class + + def perform_binding(self, serializer): + raise NotImplemented + + def perform_unbinding(self, serializer): + raise NotImplemented + + @action(methods=['post', 'delete'], detail=True, url_path='bind-object') + def bind_object(self, request, pk=None): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + if request.method == 'POST': + self.perform_binding(serializer) + return Response(serializer.data, status=status.HTTP_201_CREATED) + elif request.method == 'DELETE': + self.perform_unbinding(serializer) + return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file From a17e83ebe5001d7a22460c8406062f875c8c4fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Wed, 20 Nov 2019 16:36:37 +0300 Subject: [PATCH 2/2] On sync elasticsearch --- project/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/settings/base.py b/project/settings/base.py index 9c365b52..fba7f4b4 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -503,4 +503,4 @@ ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood', NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership'] INTERNATIONAL_COUNTRY_CODES = ['www', 'main', 'next'] -ELASTICSEARCH_DSL_AUTOSYNC = False \ No newline at end of file +#ELASTICSEARCH_DSL_AUTOSYNC = False