mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-29 13:04:03 +03:00
Allow no queryset when get_queryset overridden
The user may wish to provide a dynamic queryset on a `RelatedField` based on the `context`. The way to do that is to create a subclass of `RelatedField` (or a child) and override the `get_queryset` method. However, this is undocumented, and instantiating that field without a `queryset` argument (because it's not needed) will raise an assertion error. Document `.get_queryset(self)` as an official part of the API of `RelatedField`, and don't enforce the use of `queryset` when `get_queryset` is overridden.
This commit is contained in:
parent
2704036ad5
commit
f2452936e9
|
@ -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.
|
||||||
|
|
|
@ -62,10 +62,6 @@ 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, '
|
|
||||||
'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`.'
|
||||||
|
@ -112,6 +108,10 @@ class RelatedField(Field):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = self.queryset
|
queryset = self.queryset
|
||||||
|
assert queryset is not None, (
|
||||||
|
'Relational field must provide a `queryset` argument, '
|
||||||
|
'or set read_only=`True`.'
|
||||||
|
)
|
||||||
if isinstance(queryset, (QuerySet, Manager)):
|
if isinstance(queryset, (QuerySet, Manager)):
|
||||||
# Ensure queryset is re-evaluated whenever used.
|
# Ensure queryset is re-evaluated whenever used.
|
||||||
# Note that actually a `Manager` class may also be used as the
|
# Note that actually a `Manager` class may also be used as the
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user