Commit 33be4b43 by Tom Christie

`queryset` argument is now optional on writable model fields.

parent ccd5f295
...@@ -64,6 +64,7 @@ To run the tests. ...@@ -64,6 +64,7 @@ To run the tests.
**Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0. **Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0.
* **Serializer `instance` and `data` keyword args have their position swapped.** * **Serializer `instance` and `data` keyword args have their position swapped.**
* `queryset` argument is now optional on writable model fields.
* Support Django's cache framework. * Support Django's cache framework.
* Minor field improvements. (Don't stringify dicts, more robust many-pk fields.) * Minor field improvements. (Don't stringify dicts, more robust many-pk fields.)
* Bugfixes (Support choice field in Browseable API) * Bugfixes (Support choice field in Browseable API)
......
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
**Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0. **Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0.
* **Serializer `instance` and `data` keyword args have their position swapped.** * **Serializer `instance` and `data` keyword args have their position swapped.**
* `queryset` argument is now optional on writable model fields.
* Support Django's cache framework. * Support Django's cache framework.
* Minor field improvements. (Don't stringify dicts, more robust many-pk fields.) * Minor field improvements. (Don't stringify dicts, more robust many-pk fields.)
* Bugfixes (Support choice field in Browseable API) * Bugfix: Support choice field in Browseable API.
* Bugfix: Related fields with `read_only=True` do not require a `queryset` argument.
## 2.0.2 ## 2.0.2
......
...@@ -40,7 +40,7 @@ class Field(object): ...@@ -40,7 +40,7 @@ class Field(object):
self.source = source self.source = source
def initialize(self, parent): def initialize(self, parent, field_name):
""" """
Called to set up a field prior to field_to_native or field_from_native. Called to set up a field prior to field_to_native or field_from_native.
...@@ -248,7 +248,22 @@ class RelatedField(WritableField): ...@@ -248,7 +248,22 @@ class RelatedField(WritableField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.queryset = kwargs.pop('queryset', None) self.queryset = kwargs.pop('queryset', None)
super(RelatedField, self).__init__(*args, **kwargs) super(RelatedField, self).__init__(*args, **kwargs)
self.read_only = self.default_read_only self.read_only = kwargs.pop('read_only', self.default_read_only)
def initialize(self, parent, field_name):
super(RelatedField, self).initialize(parent, field_name)
if self.queryset is None and not self.read_only:
try:
manager = getattr(self.parent.opts.model, self.source or field_name)
if hasattr(manager, 'related'): # Forward
self.queryset = manager.related.model._default_manager.all()
else: # Reverse
self.queryset = manager.field.rel.to._default_manager.all()
except:
raise
msg = ('Serializer related fields must include a `queryset`' +
' argument or set `read_only=True')
raise Exception(msg)
### We need this stuff to make form choices work... ### We need this stuff to make form choices work...
......
...@@ -93,8 +93,8 @@ class BaseSerializer(Field): ...@@ -93,8 +93,8 @@ class BaseSerializer(Field):
def __init__(self, instance=None, data=None, context=None, **kwargs): def __init__(self, instance=None, data=None, context=None, **kwargs):
super(BaseSerializer, self).__init__(**kwargs) super(BaseSerializer, self).__init__(**kwargs)
self.fields = copy.deepcopy(self.base_fields)
self.opts = self._options_class(self.Meta) self.opts = self._options_class(self.Meta)
self.fields = copy.deepcopy(self.base_fields)
self.parent = None self.parent = None
self.root = None self.root = None
...@@ -128,7 +128,7 @@ class BaseSerializer(Field): ...@@ -128,7 +128,7 @@ class BaseSerializer(Field):
for key, field in self.fields.items(): for key, field in self.fields.items():
ret[key] = field ret[key] = field
# Set up the field # Set up the field
field.initialize(parent=self) field.initialize(parent=self, field_name=key)
# Add in the default fields # Add in the default fields
fields = self.default_fields(nested) fields = self.default_fields(nested)
...@@ -153,12 +153,12 @@ class BaseSerializer(Field): ...@@ -153,12 +153,12 @@ class BaseSerializer(Field):
##### #####
# Field methods - used when the serializer class is itself used as a field. # Field methods - used when the serializer class is itself used as a field.
def initialize(self, parent): def initialize(self, parent, field_name):
""" """
Same behaviour as usual Field, except that we need to keep track Same behaviour as usual Field, except that we need to keep track
of state so that we can deal with handling maximum depth. of state so that we can deal with handling maximum depth.
""" """
super(BaseSerializer, self).initialize(parent) super(BaseSerializer, self).initialize(parent, field_name)
if parent.opts.depth: if parent.opts.depth:
self.opts.depth = parent.opts.depth - 1 self.opts.depth = parent.opts.depth - 1
...@@ -369,7 +369,7 @@ class ModelSerializer(Serializer): ...@@ -369,7 +369,7 @@ class ModelSerializer(Serializer):
field = self.get_field(model_field) field = self.get_field(model_field)
if field: if field:
field.initialize(parent=self) field.initialize(parent=self, field_name=model_field.name)
ret[model_field.name] = field ret[model_field.name] = field
return ret return ret
......
...@@ -7,12 +7,13 @@ from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, Blo ...@@ -7,12 +7,13 @@ from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, Blo
factory = RequestFactory() factory = RequestFactory()
class BlogPostCommentSerializer(serializers.Serializer): class BlogPostCommentSerializer(serializers.ModelSerializer):
text = serializers.CharField() text = serializers.CharField()
blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail', queryset=BlogPost.objects.all()) blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail')
def restore_object(self, attrs, instance=None): class Meta:
return BlogPostComment(**attrs) model = BlogPostComment
fields = ('text', 'blog_post_url')
class BasicList(generics.ListCreateAPIView): class BasicList(generics.ListCreateAPIView):
...@@ -42,7 +43,7 @@ class ManyToManyDetail(generics.RetrieveAPIView): ...@@ -42,7 +43,7 @@ class ManyToManyDetail(generics.RetrieveAPIView):
class BlogPostCommentListCreate(generics.ListCreateAPIView): class BlogPostCommentListCreate(generics.ListCreateAPIView):
model = BlogPostComment model = BlogPostComment
model_serializer_class = BlogPostCommentSerializer serializer_class = BlogPostCommentSerializer
class BlogPostDetail(generics.RetrieveAPIView): class BlogPostDetail(generics.RetrieveAPIView):
......
...@@ -15,7 +15,7 @@ class ManyToManySource(models.Model): ...@@ -15,7 +15,7 @@ class ManyToManySource(models.Model):
class ManyToManyTargetSerializer(serializers.ModelSerializer): class ManyToManyTargetSerializer(serializers.ModelSerializer):
sources = serializers.ManyPrimaryKeyRelatedField(queryset=ManyToManySource.objects.all()) sources = serializers.ManyPrimaryKeyRelatedField()
class Meta: class Meta:
model = ManyToManyTarget model = ManyToManyTarget
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment