diff options
| author | Tom Christie | 2013-03-22 17:01:06 +0000 |
|---|---|---|
| committer | Tom Christie | 2013-03-22 17:01:06 +0000 |
| commit | 13794baf7016f7d44daffb55d29e3dbc56f7612d (patch) | |
| tree | c330b1ab6eb5d7a66011e995ee8a75405eade0d5 /rest_framework/serializers.py | |
| parent | b4210f9a56fb7f8913f674aecb304da01e2e9f64 (diff) | |
| download | django-rest-framework-13794baf7016f7d44daffb55d29e3dbc56f7612d.tar.bz2 | |
Bit of extra tidying and plenty of docs
Diffstat (limited to 'rest_framework/serializers.py')
| -rw-r--r-- | rest_framework/serializers.py | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 3029cf1c..0b0c2c9c 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -110,13 +110,15 @@ class BaseSerializer(Field): _dict_class = SortedDictWithMetadata def __init__(self, instance=None, data=None, files=None, - context=None, partial=False, many=None, source=None): + context=None, partial=False, many=None, source=None, + allow_delete=False): super(BaseSerializer, self).__init__(source=source) self.opts = self._options_class(self.Meta) self.parent = None self.root = None self.partial = partial self.many = many + self.allow_delete = allow_delete self.context = context or {} @@ -130,6 +132,12 @@ class BaseSerializer(Field): self._errors = None self._deleted = None + if many and instance is not None and not hasattr(instance, '__iter__'): + raise ValueError('instance should be a queryset or other iterable with many=True') + + if allow_delete and not many: + raise ValueError('allow_delete should only be used for bulk updates, but you have not set many=True') + ##### # Methods to determine which fields to use when (de)serializing objects. @@ -336,8 +344,15 @@ class BaseSerializer(Field): """ This hook is required for bulk update. It is used to determine the canonical identity of a given object. + + Note that the data has not been validated at this point, so we need + to make sure that we catch any cases of incorrect datatypes being + passed to this method. """ - return data.get('id') + try: + return data.get('id', None) + except AttributeError: + return None @property def errors(self): @@ -371,22 +386,12 @@ class BaseSerializer(Field): identities = [self.get_identity(self.to_native(obj)) for obj in objects] identity_to_objects = dict(zip(identities, objects)) - try: - iter(data) - if isinstance(data, dict): - raise TypeError - except TypeError: - self._errors = {'non_field_errors': ['Expected a list of items']} - else: + if hasattr(data, '__iter__') and not isinstance(data, (dict, six.text_type)): for item in data: if update: # Determine which object we're updating - try: - identity = self.get_identity(item) - except: - self.object = None - else: - self.object = identity_to_objects.pop(identity, None) + identity = self.get_identity(item) + self.object = identity_to_objects.pop(identity, None) ret.append(self.from_native(item, None)) errors.append(self._errors) @@ -395,6 +400,8 @@ class BaseSerializer(Field): self._deleted = identity_to_objects.values() self._errors = any(errors) and errors or [] + else: + self._errors = {'non_field_errors': ['Expected a list of items']} else: ret = self.from_native(data, files) @@ -445,7 +452,7 @@ class BaseSerializer(Field): else: self.save_object(self.object, **kwargs) - if self._deleted: + if self.allow_delete and self._deleted: [self.delete_object(item) for item in self._deleted] return self.object @@ -736,3 +743,13 @@ class HyperlinkedModelSerializer(ModelSerializer): 'many': to_many } return HyperlinkedRelatedField(**kwargs) + + def get_identity(self, data): + """ + This hook is required for bulk update. + We need to override the default, to use the url as the identity. + """ + try: + return data.get('url', None) + except AttributeError: + return None |
