From a1ed3a329163c1edbb802dec8e6646bea866e510 Mon Sep 17 00:00:00 2001 From: Guillaume Vincent Date: Mon, 12 Mar 2018 10:34:17 +0100 Subject: [PATCH] Fix HyperLinkedRelatedFields serializers and fields This makes the HyperLinkedRelatedFields work as they are intended to. Change-Id: I6c9556a4ad6127471dc7cb2139c32c1d74a36704 --- api/serializers.py | 137 +++++++++++++++++++++++---------------------- api/urls.py | 30 +++------- api/views.py | 53 ++++++++---------- ara/urls.py | 2 +- 4 files changed, 101 insertions(+), 121 deletions(-) diff --git a/api/serializers.py b/api/serializers.py index bddf5c9..d371a4f 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -6,7 +6,6 @@ import zlib from api import models from django.utils import timezone from rest_framework import serializers -from rest_framework.exceptions import ValidationError DATE_FORMAT = "(iso-8601: 2016-05-06T17:20:25.749489-04:00)" DURATION_FORMAT = "([DD] [HH:[MM:]]ss[.uuuuuu])" @@ -42,10 +41,12 @@ class BaseSerializer(serializers.ModelSerializer): Serializer for the data in the model base """ created = serializers.DateTimeField( - read_only=True, help_text='Date of creation %s' % DATE_FORMAT + read_only=True, + help_text='Date of creation %s' % DATE_FORMAT ) updated = serializers.DateTimeField( - read_only=True, help_text='Date of last update %s' % DATE_FORMAT + read_only=True, + help_text='Date of last update %s' % DATE_FORMAT ) age = serializers.DurationField( read_only=True, @@ -87,15 +88,15 @@ class DurationSerializer(serializers.ModelSerializer): abstract = True -class PlaybookSerializer(BaseSerializer, DurationSerializer): +class PlaybookSerializer(serializers.HyperlinkedModelSerializer, BaseSerializer): class Meta: model = models.Playbook fields = '__all__' plays = serializers.HyperlinkedRelatedField( many=True, + view_name='play-detail', read_only=True, - view_name='plays', help_text='Plays associated to this playbook' ) # tasks = serializers.HyperlinkedRelatedField( @@ -128,11 +129,11 @@ class PlaybookSerializer(BaseSerializer, DurationSerializer): # view_name='files', # help_text='Records associated to this playbook' # ) - - parameters = CompressedObjectField( - initial={}, - help_text='A JSON dictionary containing Ansible command parameters' - ) +# +# parameters = CompressedObjectField( +# initial={}, +# help_text='A JSON dictionary containing Ansible command parameters' +# ) path = serializers.CharField(help_text='Path to the playbook file') ansible_version = serializers.CharField( help_text='Version of Ansible used to run this playbook' @@ -147,61 +148,61 @@ class PlaySerializer(BaseSerializer, DurationSerializer): model = models.Play fields = '__all__' - -class TaskSerializer(BaseSerializer, DurationSerializer): - class Meta: - model = models.Task - fields = '__all__' - - -class HostSerializer(BaseSerializer): - class Meta: - model = models.Host - fields = '__all__' - - -class ResultSerializer(BaseSerializer, DurationSerializer): - class Meta: - model = models.Result - fields = '__all__' - - -class RecordSerializer(BaseSerializer): - class Meta: - model = models.Record - fields = '__all__' - - -class FileContentSerializer(BaseSerializer): - class Meta: - model = models.FileContent - fields = ('contents', 'sha1') - - contents = CompressedTextField(help_text='Contents of the file') - sha1 = serializers.CharField(read_only=True, help_text='sha1 of the file') - - def create(self, validated_data): - sha1 = hashlib.sha1(validated_data['contents']).hexdigest() - validated_data['sha1'] = sha1 - obj, created = models.FileContent.objects.get_or_create( - **validated_data - ) - return obj - - -class FileSerializer(BaseSerializer): - path = serializers.CharField(help_text='Path to the file') - content = FileContentSerializer() - - def create(self, validated_data): - contents = validated_data.pop('content')['contents'] - obj, created = models.FileContent.objects.get_or_create( - contents=contents, - sha1=hashlib.sha1(contents).hexdigest() - ) - validated_data['content'] = obj - return models.File.objects.create(**validated_data) - - class Meta: - model = models.File - fields = ('id', 'path', 'content', 'playbook') +# +# class TaskSerializer(BaseSerializer, DurationSerializer): +# class Meta: +# model = models.Task +# fields = '__all__' +# +# +# class HostSerializer(BaseSerializer): +# class Meta: +# model = models.Host +# fields = '__all__' +# +# +# class ResultSerializer(BaseSerializer, DurationSerializer): +# class Meta: +# model = models.Result +# fields = '__all__' +# +# +# class RecordSerializer(BaseSerializer): +# class Meta: +# model = models.Record +# fields = '__all__' +# +# +# class FileContentSerializer(BaseSerializer): +# class Meta: +# model = models.FileContent +# fields = ('contents', 'sha1') +# +# contents = CompressedTextField(help_text='Contents of the file') +# sha1 = serializers.CharField(read_only=True, help_text='sha1 of the file') +# +# def create(self, validated_data): +# sha1 = hashlib.sha1(validated_data['contents']).hexdigest() +# validated_data['sha1'] = sha1 +# obj, created = models.FileContent.objects.get_or_create( +# **validated_data +# ) +# return obj +# +# +# class FileSerializer(BaseSerializer): +# path = serializers.CharField(help_text='Path to the file') +# content = FileContentSerializer() +# +# def create(self, validated_data): +# contents = validated_data.pop('content')['contents'] +# obj, created = models.FileContent.objects.get_or_create( +# contents=contents, +# sha1=hashlib.sha1(contents).hexdigest() +# ) +# validated_data['content'] = obj +# return models.File.objects.create(**validated_data) +# +# class Meta: +# model = models.File +# fields = ('id', 'path', 'content', 'playbook') diff --git a/api/urls.py b/api/urls.py index e35f48d..8ac8e11 100644 --- a/api/urls.py +++ b/api/urls.py @@ -15,28 +15,16 @@ # You should have received a copy of the GNU General Public License # along with ARA. If not, see . -from django.conf.urls import url, include -from rest_framework.routers import DefaultRouter - +from django.conf.urls import url +from rest_framework.urlpatterns import format_suffix_patterns from api import views -REST_FRAMEWORK = { - # Use URL-based versioning - 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', - 'DEFAULT_VERSION': 'v1', - 'ALLOWED_VERSIONS': {'v1'}, -} - -router = DefaultRouter() -router.register(r'playbooks', views.PlaybookViewSet) -router.register(r'plays', views.PlayViewSet) -router.register(r'tasks', views.TaskViewSet) -router.register(r'hosts', views.HostViewSet) -router.register(r'results', views.ResultViewSet) -router.register(r'records', views.RecordViewSet) -router.register(r'files', views.FileViewSet) -# router.register(r'filecontent', views.FileContentViewSet) - urlpatterns = [ - url(r'^(?P[v1]+)/', include(router.urls)), + url(r'^$', views.api_root), + url(r'^playbooks/$', views.PlaybookList.as_view(), name='playbook-list'), + url(r'^playbooks/(?P[0-9]+)/$', views.PlaybookDetail.as_view(), name='playbook-detail'), + url(r'^plays/$', views.PlayList.as_view(), name='play-list'), + url(r'^plays/(?P[0-9]+)/$', views.PlayDetail.as_view(), name='play-detail'), ] + +urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/api/views.py b/api/views.py index 211d7c9..1226366 100644 --- a/api/views.py +++ b/api/views.py @@ -14,47 +14,38 @@ # # You should have received a copy of the GNU General Public License # along with ARA. If not, see . +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework.reverse import reverse from api import models, serializers -from rest_framework import viewsets +from rest_framework import generics -class PlaybookViewSet(viewsets.ModelViewSet): +@api_view(['GET']) +def api_root(request, format=None): + return Response({ + 'playbooks': reverse('playbook-list', request=request, format=format), + 'plays': reverse('play-list', request=request, format=format) + }) + + +class PlaybookList(generics.ListCreateAPIView): queryset = models.Playbook.objects.all() serializer_class = serializers.PlaybookSerializer -class PlayViewSet(viewsets.ModelViewSet): +class PlaybookDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = models.Playbook.objects.all() + serializer_class = serializers.PlaybookSerializer + + +class PlayList(generics.ListCreateAPIView): queryset = models.Play.objects.all() serializer_class = serializers.PlaySerializer -class TaskViewSet(viewsets.ModelViewSet): - queryset = models.Task.objects.all() - serializer_class = serializers.TaskSerializer - - -class HostViewSet(viewsets.ModelViewSet): - queryset = models.Host.objects.all() - serializer_class = serializers.HostSerializer - - -class ResultViewSet(viewsets.ModelViewSet): - queryset = models.Result.objects.all() - serializer_class = serializers.ResultSerializer - - -class RecordViewSet(viewsets.ModelViewSet): - queryset = models.Record.objects.all() - serializer_class = serializers.RecordSerializer - - -# class FileContentViewSet(viewsets.ModelViewSet): -# queryset = models.FileContent.objects.all() -# serializer_class = serializers.FileContentSerializer - - -class FileViewSet(viewsets.ModelViewSet): - queryset = models.File.objects.all() - serializer_class = serializers.FileSerializer +class PlayDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = models.Play.objects.all() + serializer_class = serializers.PlaySerializer diff --git a/ara/urls.py b/ara/urls.py index 348aac6..13efa84 100644 --- a/ara/urls.py +++ b/ara/urls.py @@ -7,7 +7,7 @@ admin.site.site_header = 'Administration' admin.site.index_title = 'Administration Ara' routes = [ - url(r'^api/', include('api.urls')), + url(r'^api/v1/', include('api.urls')), url(r'^admin/', admin.site.urls), ] urlpatterns = routes + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)