From 48f9fd516dd0e5226db97a3be94f8fc33d33bea7 Mon Sep 17 00:00:00 2001 From: Qwann Date: Sat, 22 Jul 2017 00:56:30 +0200 Subject: [PATCH] EventSpecificSerializer and EventSpecificViewSet defined --- api/event/serializers.py | 53 ++++++++++++++++++++++------------------ api/event/views.py | 53 +++++++++++++++++++++++----------------- api/urls.py | 4 +-- 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/api/event/serializers.py b/api/event/serializers.py index 52d898c..db84ebd 100644 --- a/api/event/serializers.py +++ b/api/event/serializers.py @@ -1,7 +1,34 @@ +from django.shortcuts import get_object_or_404 from rest_framework import serializers from event.models import Event, ActivityTag, Place, ActivityTemplate +# Classes utilitaires +class EventSpecificSerializer(serializers.HyperlinkedModelSerializer): + """ + Provide `update` and `create` methods for nested view with an Event + For example for Models which exetends EventSpecificMixin + the event id has to be provided in the `save` method + Works fine with view.EventSpecificViewSet + """ + def update(self, instance, validated_data): + """ + Note : does NOT change the event value of the instance + """ + validated_data.pop('event_pk') + [setattr(instance, key, value) + for key, value in validated_data.items()] + instance.save() + return instance + + def create(self, validated_data): + ModelClass = self.Meta.model + event_pk = validated_data.pop('event_pk', None) + event = get_object_or_404(Event, id=event_pk) + instance = ModelClass.objects.create(event=event, **validated_data) + return instance + + class EventSerializer(serializers.HyperlinkedModelSerializer): created_by = serializers.ReadOnlyField(source='created_by.username') @@ -12,35 +39,13 @@ class EventSerializer(serializers.HyperlinkedModelSerializer): # TODO rajouter des permissions -class PlaceSerializer(serializers.HyperlinkedModelSerializer): - event = EventSerializer(allow_null=True) +class PlaceSerializer(EventSpecificSerializer): + event = EventSerializer(allow_null=True, read_only=True) class Meta: model = Place fields = ('url', 'id', 'name', 'description', 'event') - def update(self, instance, validated_data): - try: - data = validated_data.pop('event') - event = Event.objects.get_object_or_404(**data) - except KeyError: - event = None - [setattr(instance, key, value) - for key, value in validated_data.items()] - setattr(instance, 'event', event) - instance.save() - return instance - - def create(self, validated_data): - ModelClass = self.Meta.model - try: - data = validated_data.pop('event') - event = Event.objects.get_object_or_404(**data) - except KeyError: - event = None - instance = ModelClass.objects.create(event=event, **validated_data) - return instance - # TODO rajouter des permissions class ActivityTagSerializer(serializers.HyperlinkedModelSerializer): diff --git a/api/event/views.py b/api/event/views.py index 5e3b210..8060219 100644 --- a/api/event/views.py +++ b/api/event/views.py @@ -1,15 +1,42 @@ from django.contrib.auth import get_user_model +from django.db.models import Q -from rest_framework.viewsets import ModelViewSet, ViewSet +from rest_framework.viewsets import ModelViewSet from api.event.serializers import EventSerializer, PlaceSerializer,\ ActivityTagSerializer, ActivityTemplateSerializer -from api.event.mixins import EventNestedMixin from event.models import Event, Place, ActivityTag, ActivityTemplate User = get_user_model() +# classes utilitaires +class EventSpecificViewSet(ModelViewSet): + """ + ViewSet that returns : + * rootlevel objects if no Event is specified + * OR objects related to the specidied event + AND root level objects + if an event is specified it passes the event_pk + to the save method. Works fine with serializers.EventSpecificSerializer + Useful for models that exetends EventSpecificMixin + """ + def get_queryset(self): + """ + Warning : You may want to override this method + and not call with super + """ + event_pk = self.kwargs.get('event_pk') + queryset = super().get_queryset() + if event_pk: + return queryset.filter(Q(event=event_pk) | Q(event=None)) + return queryset.filter(event=None) + + def perform_create(self, serializer): + event_pk = self.kwargs.get('event_pk') + serializer.save(event_pk=event_pk) + + class EventViewSet(ModelViewSet): """ This viewset automatically provides `list`, `create`, `retrieve`, @@ -23,31 +50,11 @@ class EventViewSet(ModelViewSet): serializer.save(created_by=self.request.user) -class PlaceViewSet(ModelViewSet): - """ - This viewset automatically provides `list`, `create`, `retrieve`, - `update` and `destroy` actions. - - """ +class PlaceViewSet(EventSpecificViewSet): queryset = Place.objects.all() serializer_class = PlaceSerializer -class PlaceEventViewSet(ModelViewSet): - queryset = Place.objects.all() - serializer_class = PlaceSerializer - - def list(self, request, event_pk=None): - queryset = self.queryset.filter(event=event_pk) - page = self.paginate_queryset(queryset) - if page is not None: - serializer = self.get_serializer(page, many=True) - return self.get_paginated_response(serializer.data) - - serializer = self.get_serializer(queryset, many=True) - return Response(serializer.data) - - class ActivityTagViewSet(ModelViewSet): """ This viewset automatically provides `list`, `create`, `retrieve`, diff --git a/api/urls.py b/api/urls.py index b7c60cc..9c2b0a4 100644 --- a/api/urls.py +++ b/api/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url, include from rest_framework_nested.routers import SimpleRouter, NestedSimpleRouter from api.event.views import EventViewSet, PlaceViewSet, ActivityTagViewSet,\ - ActivityTemplateViewSet, PlaceEventViewSet + ActivityTemplateViewSet # Create a router and register our viewsets with it. router = SimpleRouter() @@ -12,7 +12,7 @@ router.register(r'activitytemplate', ActivityTemplateViewSet) # Register nested router and register someviewsets vith it event_router = NestedSimpleRouter(router, r'event', lookup='event') -event_router.register(r'place', PlaceEventViewSet, base_name='event-names') +event_router.register(r'place', PlaceViewSet, base_name='event-names') # The API URLs are now determined automatically by the router.