44# SPDX-License-Identifier: GPL-2.0-or-later
55
66from rest_framework .generics import ListAPIView
7- from rest_framework .generics import RetrieveAPIView
8- from rest_framework .serializers import (
9- SerializerMethodField ,
10- HyperlinkedRelatedField ,
11- )
7+ from rest_framework .generics import RetrieveUpdateAPIView
8+ from rest_framework .serializers import SerializerMethodField
9+ from rest_framework .serializers import HyperlinkedRelatedField
10+ from rest_framework .serializers import ValidationError
1211
1312from patchwork .api .base import BaseHyperlinkedModelSerializer
1413from patchwork .api .base import PatchworkPermission
@@ -34,8 +33,9 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer):
3433 read_only = True , view_name = 'api-series-detail' , many = True
3534 )
3635 supersedes = HyperlinkedRelatedField (
37- read_only = True ,
3836 view_name = 'api-series-detail' ,
37+ queryset = Series .objects .all (),
38+ required = False ,
3939 many = True ,
4040 )
4141 superseded = HyperlinkedRelatedField (
@@ -44,6 +44,32 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer):
4444 many = True ,
4545 )
4646
47+ def update (self , instance , validated_data , * args , ** kwargs ):
48+ allowed_fields = {'supersedes' }
49+ incoming_fields = set (validated_data .keys ())
50+
51+ if not incoming_fields .issubset (allowed_fields ):
52+ invalid_fields = incoming_fields - allowed_fields
53+ raise ValidationError (
54+ {
55+ 'detail' : 'Cannot update fields: '
56+ f"{ ', ' .join (invalid_fields )} . Only 'supersedes' can be "
57+ 'updated.'
58+ }
59+ )
60+
61+ if 'supersedes' in validated_data :
62+ supersedes = validated_data .pop ('supersedes' , [])
63+
64+ try :
65+ instance .supersedes .set (supersedes )
66+ except Series .DoesNotExist :
67+ raise ValidationError (
68+ {'detail' : 'Unable to find one of the referenced series' }
69+ )
70+
71+ return instance
72+
4773 def get_web_url (self , instance ):
4874 request = self .context .get ('request' )
4975 return request .build_absolute_uri (instance .get_absolute_url ())
@@ -100,7 +126,6 @@ class Meta:
100126 'patches' ,
101127 'dependencies' ,
102128 'dependents' ,
103- 'supersedes' ,
104129 'superseded' ,
105130 )
106131 versioned_fields = {
@@ -140,7 +165,25 @@ class SeriesList(SeriesMixin, ListAPIView):
140165 ordering = 'id'
141166
142167
143- class SeriesDetail (SeriesMixin , RetrieveAPIView ):
144- """Show a series."""
168+ class SeriesDetail (SeriesMixin , RetrieveUpdateAPIView ):
169+ """Show a series.
170+
171+ retrieve:
172+ Return the details of a series.
173+
174+ update:
175+ Only updates the 'supersedes' field of a series. Replaces the whole set of
176+ superseded series.
177+
178+ Example:
179+ Instance:
180+ instance.supersedes = ['http://example.com/api/series/1/', 'http://example.com/api/series/2/', 'http://example.com/api/series/5/']
181+ Request:
182+ PUT/PATCH {"supersedes": ['http://example.com/api/series/1/', 'http://example.com/api/series/8/']}
183+ Result:
184+ instance.supersedes = ['http://example.com/api/series/1/', 'http://example.com/api/series/8/']
185+ """
145186
146- pass
187+ # PUT operation will behave as a partial update
188+ def put (self , request , * args , ** kwargs ):
189+ return self .partial_update (request , * args , ** kwargs )
0 commit comments