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.
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -294,15 +294,14 @@ To write a class-based validator, use the `__call__` method. Class-based validat
|
|||
#### Accessing the context
|
||||
|
||||
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
|
||||
`rest_framework.validators.ContextBasedValidator` as a base class for the
|
||||
validator. The `__call__` method will then be called with the `serializer_field`
|
||||
field it is being used with as additional context. You can do so by setting
|
||||
a `requires_context = True` attribute on the validator. The `__call__` method
|
||||
will then be called with the `serializer_field`
|
||||
or `serializer` as an additional argument.
|
||||
|
||||
def __call__(self, value, serializer_field):
|
||||
# Determine if this is an update or a create operation.
|
||||
is_update = serializer_field.parent.instance is not None
|
||||
requires_context = True
|
||||
|
||||
pass # implementation of the validator that uses `is_update`
|
||||
def __call__(self, value, serializer_field):
|
||||
...
|
||||
|
||||
[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
|
||||
operations.
|
||||
"""
|
||||
requires_context = True
|
||||
|
||||
def __init__(self, default):
|
||||
self.default = default
|
||||
|
||||
def set_context(self, serializer_field):
|
||||
self.is_update = serializer_field.parent.instance is not None
|
||||
if callable(self.default) and hasattr(self.default, 'set_context') and not self.is_update:
|
||||
self.default.set_context(serializer_field)
|
||||
|
||||
def __call__(self):
|
||||
if self.is_update:
|
||||
def __call__(self, serializer_field):
|
||||
is_update = serializer_field.parent.instance is not None
|
||||
if is_update:
|
||||
raise SkipField()
|
||||
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
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -270,11 +281,10 @@ class CreateOnlyDefault:
|
|||
|
||||
|
||||
class CurrentUserDefault:
|
||||
def set_context(self, serializer_field):
|
||||
self.user = serializer_field.context['request'].user
|
||||
requires_context = True
|
||||
|
||||
def __call__(self):
|
||||
return self.user
|
||||
def __call__(self, serializer_field):
|
||||
return serializer_field.context['request'].user
|
||||
|
||||
def __repr__(self):
|
||||
return '%s()' % self.__class__.__name__
|
||||
|
@ -490,8 +500,20 @@ class Field:
|
|||
raise SkipField()
|
||||
if callable(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)
|
||||
return self.default()
|
||||
|
||||
if getattr(self.default, 'requires_context', False):
|
||||
return self.default(self)
|
||||
else:
|
||||
return self.default()
|
||||
|
||||
return self.default
|
||||
|
||||
def validate_empty_values(self, data):
|
||||
|
@ -549,22 +571,20 @@ class Field:
|
|||
Test the given value against all the validators on the field,
|
||||
and either raise a `ValidationError` or simply return.
|
||||
"""
|
||||
from rest_framework.validators import ContextBasedValidator
|
||||
|
||||
errors = []
|
||||
for validator in self.validators:
|
||||
if hasattr(validator, 'set_context'):
|
||||
warnings.warn(
|
||||
"Method `set_context` on validators is deprecated and will "
|
||||
"no longer be called starting with 3.11. Instead derive the "
|
||||
"validator from `rest_framwork.validators.ContextBasedValidator` "
|
||||
"and accept the context as an additional argument.",
|
||||
"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
|
||||
)
|
||||
validator.set_context(self)
|
||||
|
||||
try:
|
||||
if isinstance(validator, ContextBasedValidator):
|
||||
if getattr(validator, 'requires_context', False):
|
||||
validator(value, self)
|
||||
else:
|
||||
validator(value)
|
||||
|
|
|
@ -30,23 +30,14 @@ def qs_filter(queryset, **kwargs):
|
|||
return queryset.none()
|
||||
|
||||
|
||||
class ContextBasedValidator:
|
||||
"""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):
|
||||
class UniqueValidator:
|
||||
"""
|
||||
Validator that corresponds to `unique=True` on a model field.
|
||||
|
||||
Should be applied to an individual field on the serializer.
|
||||
"""
|
||||
message = _('This field must be unique.')
|
||||
requires_context = True
|
||||
|
||||
def __init__(self, queryset, message=None, lookup='exact'):
|
||||
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.
|
||||
|
||||
|
@ -98,6 +89,7 @@ class UniqueTogetherValidator(ContextBasedValidator):
|
|||
"""
|
||||
message = _('The fields {field_names} must make a unique set.')
|
||||
missing_message = _('This field is required.')
|
||||
requires_context = True
|
||||
|
||||
def __init__(self, queryset, fields, message=None):
|
||||
self.queryset = queryset
|
||||
|
@ -174,9 +166,10 @@ class UniqueTogetherValidator(ContextBasedValidator):
|
|||
)
|
||||
|
||||
|
||||
class BaseUniqueForValidator(ContextBasedValidator):
|
||||
class BaseUniqueForValidator:
|
||||
message = None
|
||||
missing_message = _('This field is required.')
|
||||
requires_context = True
|
||||
|
||||
def __init__(self, queryset, field, date_field, message=None):
|
||||
self.queryset = queryset
|
||||
|
|
Loading…
Reference in New Issue
Block a user