mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-28 08:59:54 +03:00
Drop set_context() in favour of 'requires_context = True'
This commit is contained in:
parent
79475fed7e
commit
d57a40b579
|
@ -50,7 +50,19 @@ If set, this gives the default value that will be used for the field if no input
|
||||||
|
|
||||||
The `default` is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.
|
The `default` is not applied during partial update operations. In the partial update case only fields that are provided in the incoming data will have a validated value returned.
|
||||||
|
|
||||||
May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a `set_context` method, that will be called each time before getting the value with the field instance as only argument.
|
May be set to a function or other callable, in which case the value will be evaluated each time it is used. When called, it will receive no arguments. If the callable has a `requires_context = True` attribute, then the serializer field will be passed as an argument.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
class CurrentUserDefault:
|
||||||
|
"""
|
||||||
|
May be applied as a `default=...` value on a serializer field.
|
||||||
|
Returns the current user.
|
||||||
|
"""
|
||||||
|
requires_context = True
|
||||||
|
|
||||||
|
def __call__(self, serializer_field):
|
||||||
|
return serializer_field.context['request'].user
|
||||||
|
|
||||||
When serializing the instance, default will be used if the object attribute or dictionary key is not present in the instance.
|
When serializing the instance, default will be used if the object attribute or dictionary key is not present in the instance.
|
||||||
|
|
||||||
|
|
|
@ -294,15 +294,14 @@ To write a class-based validator, use the `__call__` method. Class-based validat
|
||||||
#### Accessing the context
|
#### Accessing the context
|
||||||
|
|
||||||
In some advanced cases you might want a validator to be passed the serializer
|
In some advanced cases you might want a validator to be passed the serializer
|
||||||
field it is being used with as additional context. You can do so by using
|
field it is being used with as additional context. You can do so by setting
|
||||||
`rest_framework.validators.ContextBasedValidator` as a base class for the
|
a `requires_context = True` attribute on the validator. The `__call__` method
|
||||||
validator. The `__call__` method will then be called with the `serializer_field`
|
will then be called with the `serializer_field`
|
||||||
or `serializer` as an additional argument.
|
or `serializer` as an additional argument.
|
||||||
|
|
||||||
def __call__(self, value, serializer_field):
|
requires_context = True
|
||||||
# Determine if this is an update or a create operation.
|
|
||||||
is_update = serializer_field.parent.instance is not None
|
|
||||||
|
|
||||||
pass # implementation of the validator that uses `is_update`
|
def __call__(self, value, serializer_field):
|
||||||
|
...
|
||||||
|
|
||||||
[cite]: https://docs.djangoproject.com/en/stable/ref/validators/
|
[cite]: https://docs.djangoproject.com/en/stable/ref/validators/
|
||||||
|
|
|
@ -250,19 +250,30 @@ class CreateOnlyDefault:
|
||||||
for create operations, but that do not return any value for update
|
for create operations, but that do not return any value for update
|
||||||
operations.
|
operations.
|
||||||
"""
|
"""
|
||||||
|
requires_context = True
|
||||||
|
|
||||||
def __init__(self, default):
|
def __init__(self, default):
|
||||||
self.default = default
|
self.default = default
|
||||||
|
|
||||||
def set_context(self, serializer_field):
|
def __call__(self, serializer_field):
|
||||||
self.is_update = serializer_field.parent.instance is not None
|
is_update = serializer_field.parent.instance is not None
|
||||||
if callable(self.default) and hasattr(self.default, 'set_context') and not self.is_update:
|
if is_update:
|
||||||
self.default.set_context(serializer_field)
|
|
||||||
|
|
||||||
def __call__(self):
|
|
||||||
if self.is_update:
|
|
||||||
raise SkipField()
|
raise SkipField()
|
||||||
if callable(self.default):
|
if callable(self.default):
|
||||||
return self.default()
|
if hasattr(self.default, 'set_context'):
|
||||||
|
warnings.warn(
|
||||||
|
"Method `set_context` on defaults is deprecated and will "
|
||||||
|
"no longer be called starting with 3.12. Instead set "
|
||||||
|
"`requires_context = True` on the class, and accept the "
|
||||||
|
"context as an additional argument.",
|
||||||
|
DeprecationWarning, stacklevel=2
|
||||||
|
)
|
||||||
|
self.default.set_context(self)
|
||||||
|
|
||||||
|
if getattr(self.default, 'requires_context', False):
|
||||||
|
return self.default(serializer_field)
|
||||||
|
else:
|
||||||
|
return self.default()
|
||||||
return self.default
|
return self.default
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -270,11 +281,10 @@ class CreateOnlyDefault:
|
||||||
|
|
||||||
|
|
||||||
class CurrentUserDefault:
|
class CurrentUserDefault:
|
||||||
def set_context(self, serializer_field):
|
requires_context = True
|
||||||
self.user = serializer_field.context['request'].user
|
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self, serializer_field):
|
||||||
return self.user
|
return serializer_field.context['request'].user
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s()' % self.__class__.__name__
|
return '%s()' % self.__class__.__name__
|
||||||
|
@ -490,8 +500,20 @@ class Field:
|
||||||
raise SkipField()
|
raise SkipField()
|
||||||
if callable(self.default):
|
if callable(self.default):
|
||||||
if hasattr(self.default, 'set_context'):
|
if hasattr(self.default, 'set_context'):
|
||||||
|
warnings.warn(
|
||||||
|
"Method `set_context` on defaults is deprecated and will "
|
||||||
|
"no longer be called starting with 3.12. Instead set "
|
||||||
|
"`requires_context = True` on the class, and accept the "
|
||||||
|
"context as an additional argument.",
|
||||||
|
DeprecationWarning, stacklevel=2
|
||||||
|
)
|
||||||
self.default.set_context(self)
|
self.default.set_context(self)
|
||||||
return self.default()
|
|
||||||
|
if getattr(self.default, 'requires_context', False):
|
||||||
|
return self.default(self)
|
||||||
|
else:
|
||||||
|
return self.default()
|
||||||
|
|
||||||
return self.default
|
return self.default
|
||||||
|
|
||||||
def validate_empty_values(self, data):
|
def validate_empty_values(self, data):
|
||||||
|
@ -549,22 +571,20 @@ class Field:
|
||||||
Test the given value against all the validators on the field,
|
Test the given value against all the validators on the field,
|
||||||
and either raise a `ValidationError` or simply return.
|
and either raise a `ValidationError` or simply return.
|
||||||
"""
|
"""
|
||||||
from rest_framework.validators import ContextBasedValidator
|
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
for validator in self.validators:
|
for validator in self.validators:
|
||||||
if hasattr(validator, 'set_context'):
|
if hasattr(validator, 'set_context'):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Method `set_context` on validators is deprecated and will "
|
"Method `set_context` on validators is deprecated and will "
|
||||||
"no longer be called starting with 3.11. Instead derive the "
|
"no longer be called starting with 3.12. Instead set "
|
||||||
"validator from `rest_framwork.validators.ContextBasedValidator` "
|
"`requires_context = True` on the class, and accept the "
|
||||||
"and accept the context as an additional argument.",
|
"context as an additional argument.",
|
||||||
DeprecationWarning, stacklevel=2
|
DeprecationWarning, stacklevel=2
|
||||||
)
|
)
|
||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if isinstance(validator, ContextBasedValidator):
|
if getattr(validator, 'requires_context', False):
|
||||||
validator(value, self)
|
validator(value, self)
|
||||||
else:
|
else:
|
||||||
validator(value)
|
validator(value)
|
||||||
|
|
|
@ -30,23 +30,14 @@ def qs_filter(queryset, **kwargs):
|
||||||
return queryset.none()
|
return queryset.none()
|
||||||
|
|
||||||
|
|
||||||
class ContextBasedValidator:
|
class UniqueValidator:
|
||||||
"""Base class for validators that need a context during evaluation.
|
|
||||||
|
|
||||||
In extension to regular validators their `__call__` method must not only
|
|
||||||
accept a value, but also an instance of a serializer.
|
|
||||||
"""
|
|
||||||
def __call__(self, value, serializer):
|
|
||||||
raise NotImplementedError('`__call__()` must be implemented.')
|
|
||||||
|
|
||||||
|
|
||||||
class UniqueValidator(ContextBasedValidator):
|
|
||||||
"""
|
"""
|
||||||
Validator that corresponds to `unique=True` on a model field.
|
Validator that corresponds to `unique=True` on a model field.
|
||||||
|
|
||||||
Should be applied to an individual field on the serializer.
|
Should be applied to an individual field on the serializer.
|
||||||
"""
|
"""
|
||||||
message = _('This field must be unique.')
|
message = _('This field must be unique.')
|
||||||
|
requires_context = True
|
||||||
|
|
||||||
def __init__(self, queryset, message=None, lookup='exact'):
|
def __init__(self, queryset, message=None, lookup='exact'):
|
||||||
self.queryset = queryset
|
self.queryset = queryset
|
||||||
|
@ -90,7 +81,7 @@ class UniqueValidator(ContextBasedValidator):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UniqueTogetherValidator(ContextBasedValidator):
|
class UniqueTogetherValidator:
|
||||||
"""
|
"""
|
||||||
Validator that corresponds to `unique_together = (...)` on a model class.
|
Validator that corresponds to `unique_together = (...)` on a model class.
|
||||||
|
|
||||||
|
@ -98,6 +89,7 @@ class UniqueTogetherValidator(ContextBasedValidator):
|
||||||
"""
|
"""
|
||||||
message = _('The fields {field_names} must make a unique set.')
|
message = _('The fields {field_names} must make a unique set.')
|
||||||
missing_message = _('This field is required.')
|
missing_message = _('This field is required.')
|
||||||
|
requires_context = True
|
||||||
|
|
||||||
def __init__(self, queryset, fields, message=None):
|
def __init__(self, queryset, fields, message=None):
|
||||||
self.queryset = queryset
|
self.queryset = queryset
|
||||||
|
@ -174,9 +166,10 @@ class UniqueTogetherValidator(ContextBasedValidator):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseUniqueForValidator(ContextBasedValidator):
|
class BaseUniqueForValidator:
|
||||||
message = None
|
message = None
|
||||||
missing_message = _('This field is required.')
|
missing_message = _('This field is required.')
|
||||||
|
requires_context = True
|
||||||
|
|
||||||
def __init__(self, queryset, field, date_field, message=None):
|
def __init__(self, queryset, field, date_field, message=None):
|
||||||
self.queryset = queryset
|
self.queryset = queryset
|
||||||
|
|
Loading…
Reference in New Issue
Block a user