HyperlinkedIdentityField now requires View-Name

HyperlinkedModelSerializer sets View-Name on the Fly
* serializers opt class need to be set by serializers Metaclass
This commit is contained in:
Ludwig Kraatz 2012-12-04 13:25:08 +01:00
parent 3e3ede71d2
commit acaaa0384c
2 changed files with 35 additions and 7 deletions

View File

@ -634,9 +634,11 @@ class HyperlinkedIdentityField(Field):
slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# TODO: Make view_name mandatory, and have the try:
# HyperlinkedModelSerializer set it on-the-fly self.view_name = kwargs.pop('view_name')
self.view_name = kwargs.pop('view_name', None) except:
raise ValueError("Hyperlinked Identity field requires 'view_name' kwarg")
self.format = kwargs.pop('format', None) self.format = kwargs.pop('format', None)
self.slug_field = kwargs.pop('slug_field', self.slug_field) self.slug_field = kwargs.pop('slug_field', self.slug_field)

View File

@ -5,6 +5,8 @@ from decimal import Decimal
from django.db import models from django.db import models
from django.forms import widgets from django.forms import widgets
from django.utils.datastructures import SortedDict from django.utils.datastructures import SortedDict
from django.utils.functional import empty
from django.core.exceptions import ImproperlyConfigured
from rest_framework.compat import get_concrete_model from rest_framework.compat import get_concrete_model
# Note: We do the following so that users of the framework can use this style: # Note: We do the following so that users of the framework can use this style:
@ -67,10 +69,34 @@ def _get_declared_fields(bases, attrs):
return SortedDict(fields) return SortedDict(fields)
def _get_options_instance(bases, attrs):
options_class = Meta = empty
if '_options_class' in attrs:
options_class = attrs['_options_class']
else:
for base in bases:
if hasattr(base, '_options_class'):
options_class = getattr(base, '_options_class')
break
if options_class is empty:
raise ImproperlyConfigured, 'A Serializer requires an "_options_class" attribute'
if 'Meta' in attrs:
Meta = attrs['Meta']
else:
for base in bases:
if hasattr(base, 'Meta'):
Meta = getattr(base, 'Meta')
break
if Meta is empty:
raise ImproperlyConfigured, 'A Serializer requires an "Meta" attribute'
return options_class(Meta)
class SerializerMetaclass(type): class SerializerMetaclass(type):
def __new__(cls, name, bases, attrs): def __new__(cls, name, bases, attrs):
attrs['base_fields'] = _get_declared_fields(bases, attrs) attrs['base_fields'] = _get_declared_fields(bases, attrs)
attrs['opts'] = _get_options_instance(bases, attrs)
return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs) return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs)
@ -93,7 +119,6 @@ class BaseSerializer(Field):
def __init__(self, instance=None, data=None, files=None, context=None, partial=False, **kwargs): def __init__(self, instance=None, data=None, files=None, context=None, partial=False, **kwargs):
super(BaseSerializer, self).__init__(**kwargs) super(BaseSerializer, self).__init__(**kwargs)
self.opts = self._options_class(self.Meta)
self.parent = None self.parent = None
self.root = None self.root = None
self.partial = partial self.partial = partial
@ -503,13 +528,14 @@ class HyperlinkedModelSerializer(ModelSerializer):
_options_class = HyperlinkedModelSerializerOptions _options_class = HyperlinkedModelSerializerOptions
_default_view_name = '%(model_name)s-detail' _default_view_name = '%(model_name)s-detail'
url = HyperlinkedIdentityField()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(HyperlinkedModelSerializer, self).__init__(*args, **kwargs)
if self.opts.view_name is None: if self.opts.view_name is None:
self.opts.view_name = self._get_default_view_name(self.opts.model) self.opts.view_name = self._get_default_view_name(self.opts.model)
self.base_fields.insert(0, 'url', HyperlinkedIdentityField(view_name=self.opts.view_name))
super(HyperlinkedModelSerializer, self).__init__(*args, **kwargs)
def _get_default_view_name(self, model): def _get_default_view_name(self, model):
""" """
Return the view name to use if 'view_name' is not specified in 'Meta' Return the view name to use if 'view_name' is not specified in 'Meta'