Merge pull request #3605 from ryanhiebert/slug-related-field-queryset

RelatedField get_queryset and context
This commit is contained in:
Xavier Ordoquy 2016-01-20 18:17:29 +01:00
commit f1b28b4d63
3 changed files with 25 additions and 4 deletions

View File

@ -330,6 +330,8 @@ To implement a custom relational field, you should override `RelatedField`, and
If you want to implement a read-write relational field, you must also implement the `.to_internal_value(self, data)` method. If you want to implement a read-write relational field, you must also implement the `.to_internal_value(self, data)` method.
To provide a dynamic queryset based on the `context`, you can also override `.get_queryset(self)` instead of specifying `.queryset` on the class or when initializing the field.
## Example ## Example
For example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration. For example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration.

View File

@ -21,6 +21,15 @@ from rest_framework.reverse import reverse
from rest_framework.utils import html from rest_framework.utils import html
def method_overridden(method_name, klass, instance):
"""
Determine if a method has been overridden.
"""
method = getattr(klass, method_name)
default_method = getattr(method, '__func__', method) # Python 3 compat
return default_method is not getattr(instance, method_name).__func__
class Hyperlink(six.text_type): class Hyperlink(six.text_type):
""" """
A string like object that additionally has an associated name. A string like object that additionally has an associated name.
@ -65,10 +74,12 @@ class RelatedField(Field):
self.queryset = kwargs.pop('queryset', self.queryset) self.queryset = kwargs.pop('queryset', self.queryset)
self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff) self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text) self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)
assert self.queryset is not None or kwargs.get('read_only', None), (
'Relational field must provide a `queryset` argument, ' if not method_overridden('get_queryset', RelatedField, self):
'or set read_only=`True`.' assert self.queryset is not None or kwargs.get('read_only', None), (
) 'Relational field must provide a `queryset` argument, '
'override `get_queryset`, or set read_only=`True`.'
)
assert not (self.queryset is not None and kwargs.get('read_only', None)), ( assert not (self.queryset is not None and kwargs.get('read_only', None)), (
'Relational fields should not provide a `queryset` argument, ' 'Relational fields should not provide a `queryset` argument, '
'when setting read_only=`True`.' 'when setting read_only=`True`.'

View File

@ -176,6 +176,14 @@ class TestSlugRelatedField(APISimpleTestCase):
representation = self.field.to_representation(self.instance) representation = self.field.to_representation(self.instance)
assert representation == self.instance.name assert representation == self.instance.name
def test_no_queryset_init(self):
class NoQuerySetSlugRelatedField(serializers.SlugRelatedField):
def get_queryset(this):
return self.queryset
field = NoQuerySetSlugRelatedField(slug_field='name')
field.to_internal_value(self.instance.name)
class TestManyRelatedField(APISimpleTestCase): class TestManyRelatedField(APISimpleTestCase):
def setUp(self): def setUp(self):