This commit is contained in:
Ludwig Kraatz 2012-12-07 13:55:21 -08:00
commit 9bd59d1e8f
2 changed files with 41 additions and 13 deletions

View File

@ -570,17 +570,17 @@ class HyperlinkedRelatedField(RelatedField):
kwargs = {self.slug_url_kwarg: slug} kwargs = {self.slug_url_kwarg: slug}
try: try:
return reverse(self.view_name, kwargs=kwargs, request=request, format=format) return reverse(view_name, kwargs=kwargs, request=request, format=format)
except: except:
pass pass
kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug} kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug}
try: try:
return reverse(self.view_name, kwargs=kwargs, request=request, format=format) return reverse(view_name, kwargs=kwargs, request=request, format=format)
except: except:
pass pass
raise ValidationError('Could not resolve URL for field using view name "%s"', view_name) raise ValidationError('Could not resolve URL for field using view name "%s"' % view_name)
def from_native(self, value): def from_native(self, value):
# Convert URL -> model instance pk # Convert URL -> model instance pk
@ -640,9 +640,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)
@ -655,7 +657,7 @@ class HyperlinkedIdentityField(Field):
def field_to_native(self, obj, field_name): def field_to_native(self, obj, field_name):
request = self.context.get('request', None) request = self.context.get('request', None)
format = self.format or self.context.get('format', None) format = self.format or self.context.get('format', None)
view_name = self.view_name or self.parent.opts.view_name view_name = self.view_name
kwargs = {self.pk_url_kwarg: obj.pk} kwargs = {self.pk_url_kwarg: obj.pk}
try: try:
return reverse(view_name, kwargs=kwargs, request=request, format=format) return reverse(view_name, kwargs=kwargs, request=request, format=format)
@ -669,13 +671,13 @@ class HyperlinkedIdentityField(Field):
kwargs = {self.slug_url_kwarg: slug} kwargs = {self.slug_url_kwarg: slug}
try: try:
return reverse(self.view_name, kwargs=kwargs, request=request, format=format) return reverse(view_name, kwargs=kwargs, request=request, format=format)
except: except:
pass pass
kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug} kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug}
try: try:
return reverse(self.view_name, kwargs=kwargs, request=request, format=format) return reverse(view_name, kwargs=kwargs, request=request, format=format)
except: except:
pass pass

View File

@ -5,6 +5,7 @@ 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.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:
@ -76,10 +77,34 @@ def _get_declared_fields(bases, attrs):
return SortedDict(fields) return SortedDict(fields)
def _get_options_instance(bases, attrs):
options_class = Meta = None
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 None:
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 None:
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)
@ -102,7 +127,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
@ -548,12 +572,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)
if not 'url' in self.base_fields:
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):
""" """