mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 19:14:01 +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.
|
||||
|
||||
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
|
||||
|
||||
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.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
|
||||
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)), (
|
||||
'Relational fields should not provide a `queryset` argument, '
|
||||
'when setting read_only=`True`.'
|
||||
|
@ -112,6 +108,10 @@ class RelatedField(Field):
|
|||
|
||||
def get_queryset(self):
|
||||
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)):
|
||||
# Ensure queryset is re-evaluated whenever used.
|
||||
# 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)
|
||||
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):
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue
Block a user