Merged BaseSerializer with WagtailSerializer

Previously, WagtailSerializer and it's subclasses were responsible for serializing objects and it delegated serializing the dynamic fields to automatically generated subclasses of BaseSerializer.

Now, these have been merged and all serializers are generated automatically for a particular request. The responsibility of generating the serializers is now in the endpoint.
This commit is contained in:
Karl Hobley 2015-08-03 19:33:59 +01:00
parent 32d0170882
commit b3ca0412f5
2 changed files with 45 additions and 44 deletions

View file

@ -20,14 +20,14 @@ from .filters import (
)
from .renderers import WagtailJSONRenderer
from .pagination import WagtailPagination
from .serializers import WagtailSerializer, PageSerializer, DocumentSerializer
from .serializers import BaseSerializer, PageSerializer, DocumentSerializer, get_serializer_class
from .utils import BadRequestError
class BaseAPIEndpoint(GenericViewSet):
renderer_classes = [WagtailJSONRenderer]
pagination_class = WagtailPagination
serializer_class = WagtailSerializer
base_serializer_class = BaseSerializer
filter_classes = []
queryset = None # Set on subclasses or implement `get_queryset()`.
@ -87,18 +87,21 @@ class BaseAPIEndpoint(GenericViewSet):
if unknown_parameters:
raise BadRequestError("query parameter is not an operation or a recognised field: %s" % ', '.join(sorted(unknown_parameters)))
def get_serializer_context(self):
"""
The serialization context differs between listing and detail views.
"""
def get_serializer_class(self):
request = self.request
# Get model
if self.action == 'listing_view':
model = self.get_queryset().model
else:
model = type(self.get_object())
all_fields = self.get_api_fields(model)
all_fields = list(OrderedDict.fromkeys(all_fields)) # Removes any duplicates in case the developer put "title" in api_fields
# Get all available fields
all_fields = self.get_api_fields(model)
all_fields = list(OrderedDict.fromkeys(all_fields)) # Removes any duplicates in case the developer put "title" in api_fields
if self.action == 'listing_view':
# Listing views just show the title field and any other allowed field the user specified
if 'fields' in request.GET:
fields = set(request.GET['fields'].split(','))
else:
@ -111,22 +114,27 @@ class BaseAPIEndpoint(GenericViewSet):
# Reorder fields so it matches the order of all_fields
fields = [field for field in all_fields if field in fields]
else:
# Detail views show all fields all the time
fields = all_fields
return get_serializer_class(model, fields, base=self.base_serializer_class)
def get_serializer_context(self):
"""
The serialization context differs between listing and detail views.
"""
request = self.request
if self.action == 'listing_view':
return {
'request': request,
'view': self,
'fields': fields
}
model = type(self.get_object())
all_fields = self.get_api_fields(model)
all_fields = list(OrderedDict.fromkeys(all_fields)) # Removes any duplicates in case the developer put "title" in api_fields
return {
'request': request,
'view': self,
'fields': all_fields,
'show_details': True
}
@ -155,7 +163,7 @@ class BaseAPIEndpoint(GenericViewSet):
class PagesAPIEndpoint(BaseAPIEndpoint):
serializer_class = PageSerializer
base_serializer_class = PageSerializer
filter_backends = [
FieldsFilter,
ChildOfFilter,
@ -216,7 +224,7 @@ class ImagesAPIEndpoint(BaseAPIEndpoint):
class DocumentsAPIEndpoint(BaseAPIEndpoint):
queryset = Document.objects.all().order_by('id')
serializer_class = DocumentSerializer
base_serializer_class = DocumentSerializer
filter_backends = [FieldsFilter, OrderingFilter, SearchFilter]
extra_api_fields = ['title', 'tags']
name = 'documents'

View file

@ -14,7 +14,7 @@ from wagtail.utils.compat import get_related_model
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore import fields as wagtailcore_fields
from .utils import ObjectDetailURL, URLPath, BadRequestError, pages_for_site
from .utils import ObjectDetailURL, URLPath, pages_for_site
class ChildRelationField(Field):
@ -27,7 +27,8 @@ class ChildRelationField(Field):
serializer = serializer_class()
return [
serializer.to_representation(child_object)
# Use rest frameworks to_representation method so we don't add id/meta attributes
super(BaseSerializer, serializer).to_representation(child_object)
for child_object in value.all()
]
@ -88,24 +89,8 @@ class BaseSerializer(serializers.ModelSerializer):
return super(BaseSerializer, self).build_relational_field(field_name, relation_info)
def get_serializer_class(model_, fields_):
class Meta:
model = model_
fields = fields_
return type(model_.__name__ + 'Serializer', (BaseSerializer, ), {
'Meta': Meta
})
class WagtailSerializer(serializers.BaseSerializer):
def to_representation(self, instance):
fields = self.context.get('fields')
return self.serialize_object(
instance,
fields=fields,
)
return self.serialize_object(instance)
def serialize_object_metadata(self, obj):
"""
@ -120,7 +105,7 @@ class WagtailSerializer(serializers.BaseSerializer):
return data
def serialize_object(self, obj, fields, extra_data=()):
def serialize_object(self, obj, extra_data=()):
"""
This converts an object into JSON-serialisable dict so it can
be used in the API.
@ -138,14 +123,12 @@ class WagtailSerializer(serializers.BaseSerializer):
data.extend(extra_data)
# Serialize the fields
serializer_class = get_serializer_class(type(obj), fields)
serializer = serializer_class()
data.extend(serializer.to_representation(obj).items())
data.extend(super(BaseSerializer, self).to_representation(obj).items())
return OrderedDict(data)
class PageSerializer(WagtailSerializer):
class PageSerializer(BaseSerializer):
def serialize_object_metadata(self, page):
data = super(PageSerializer, self).serialize_object_metadata(page)
@ -154,7 +137,7 @@ class PageSerializer(WagtailSerializer):
return data
def serialize_object(self, page, fields, extra_data=()):
def serialize_object(self, page, extra_data=()):
# Add parent
if self.context.get('show_details', False):
parent = page.get_parent()
@ -173,10 +156,10 @@ class PageSerializer(WagtailSerializer):
])),
)
return super(PageSerializer, self).serialize_object(page, fields, extra_data=extra_data)
return super(PageSerializer, self).serialize_object(page, extra_data=extra_data)
class DocumentSerializer(WagtailSerializer):
class DocumentSerializer(BaseSerializer):
def serialize_object_metadata(self, document):
data = super(DocumentSerializer, self).serialize_object_metadata(document)
@ -185,3 +168,13 @@ class DocumentSerializer(WagtailSerializer):
data['download_url'] = URLPath(document.url)
return data
def get_serializer_class(model_, fields_, base=BaseSerializer):
class Meta:
model = model_
fields = fields_
return type(model_.__name__ + 'Serializer', (base, ), {
'Meta': Meta
})