mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-03 13:14:30 +03:00
Followup to set_context removal (#7076)
* Raise framework-specific deprecation warnings - Use `RemovedInDRF313Warning` instead of DeprecationWarning - Update to follow deprecation policy * Pass serializer instead of model to validator The `UniqueTogetherValidator` may need to access attributes on the serializer instead of just the model instance. For example, this is useful for handling field sources. * Fix framework deprecation warning in test * Remove outdated validator attribute
This commit is contained in:
parent
ebcd93163a
commit
de9f1d56c4
|
@ -30,7 +30,7 @@ from django.utils.timezone import utc
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from pytz.exceptions import InvalidTimeError
|
from pytz.exceptions import InvalidTimeError
|
||||||
|
|
||||||
from rest_framework import ISO_8601
|
from rest_framework import ISO_8601, RemovedInDRF313Warning
|
||||||
from rest_framework.compat import ProhibitNullCharactersValidator
|
from rest_framework.compat import ProhibitNullCharactersValidator
|
||||||
from rest_framework.exceptions import ErrorDetail, ValidationError
|
from rest_framework.exceptions import ErrorDetail, ValidationError
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
@ -263,10 +263,10 @@ class CreateOnlyDefault:
|
||||||
if hasattr(self.default, 'set_context'):
|
if hasattr(self.default, 'set_context'):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Method `set_context` on defaults is deprecated and will "
|
"Method `set_context` on defaults is deprecated and will "
|
||||||
"no longer be called starting with 3.12. Instead set "
|
"no longer be called starting with 3.13. Instead set "
|
||||||
"`requires_context = True` on the class, and accept the "
|
"`requires_context = True` on the class, and accept the "
|
||||||
"context as an additional argument.",
|
"context as an additional argument.",
|
||||||
DeprecationWarning, stacklevel=2
|
RemovedInDRF313Warning, stacklevel=2
|
||||||
)
|
)
|
||||||
self.default.set_context(self)
|
self.default.set_context(self)
|
||||||
|
|
||||||
|
@ -502,10 +502,10 @@ class Field:
|
||||||
if hasattr(self.default, 'set_context'):
|
if hasattr(self.default, 'set_context'):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Method `set_context` on defaults is deprecated and will "
|
"Method `set_context` on defaults is deprecated and will "
|
||||||
"no longer be called starting with 3.12. Instead set "
|
"no longer be called starting with 3.13. Instead set "
|
||||||
"`requires_context = True` on the class, and accept the "
|
"`requires_context = True` on the class, and accept the "
|
||||||
"context as an additional argument.",
|
"context as an additional argument.",
|
||||||
DeprecationWarning, stacklevel=2
|
RemovedInDRF313Warning, stacklevel=2
|
||||||
)
|
)
|
||||||
self.default.set_context(self)
|
self.default.set_context(self)
|
||||||
|
|
||||||
|
@ -576,10 +576,10 @@ class Field:
|
||||||
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.12. Instead set "
|
"no longer be called starting with 3.13. Instead set "
|
||||||
"`requires_context = True` on the class, and accept the "
|
"`requires_context = True` on the class, and accept the "
|
||||||
"context as an additional argument.",
|
"context as an additional argument.",
|
||||||
DeprecationWarning, stacklevel=2
|
RemovedInDRF313Warning, stacklevel=2
|
||||||
)
|
)
|
||||||
validator.set_context(self)
|
validator.set_context(self)
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ class UniqueValidator:
|
||||||
|
|
||||||
def __init__(self, queryset, message=None, lookup='exact'):
|
def __init__(self, queryset, message=None, lookup='exact'):
|
||||||
self.queryset = queryset
|
self.queryset = queryset
|
||||||
self.serializer_field = None
|
|
||||||
self.message = message or self.message
|
self.message = message or self.message
|
||||||
self.lookup = lookup
|
self.lookup = lookup
|
||||||
|
|
||||||
|
@ -94,15 +93,14 @@ class UniqueTogetherValidator:
|
||||||
def __init__(self, queryset, fields, message=None):
|
def __init__(self, queryset, fields, message=None):
|
||||||
self.queryset = queryset
|
self.queryset = queryset
|
||||||
self.fields = fields
|
self.fields = fields
|
||||||
self.serializer_field = None
|
|
||||||
self.message = message or self.message
|
self.message = message or self.message
|
||||||
|
|
||||||
def enforce_required_fields(self, attrs, instance):
|
def enforce_required_fields(self, attrs, serializer):
|
||||||
"""
|
"""
|
||||||
The `UniqueTogetherValidator` always forces an implied 'required'
|
The `UniqueTogetherValidator` always forces an implied 'required'
|
||||||
state on the fields it applies to.
|
state on the fields it applies to.
|
||||||
"""
|
"""
|
||||||
if instance is not None:
|
if serializer.instance is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
missing_items = {
|
missing_items = {
|
||||||
|
@ -113,16 +111,16 @@ class UniqueTogetherValidator:
|
||||||
if missing_items:
|
if missing_items:
|
||||||
raise ValidationError(missing_items, code='required')
|
raise ValidationError(missing_items, code='required')
|
||||||
|
|
||||||
def filter_queryset(self, attrs, queryset, instance):
|
def filter_queryset(self, attrs, queryset, serializer):
|
||||||
"""
|
"""
|
||||||
Filter the queryset to all instances matching the given attributes.
|
Filter the queryset to all instances matching the given attributes.
|
||||||
"""
|
"""
|
||||||
# If this is an update, then any unprovided field should
|
# If this is an update, then any unprovided field should
|
||||||
# have it's value set based on the existing instance attribute.
|
# have it's value set based on the existing instance attribute.
|
||||||
if instance is not None:
|
if serializer.instance is not None:
|
||||||
for field_name in self.fields:
|
for field_name in self.fields:
|
||||||
if field_name not in attrs:
|
if field_name not in attrs:
|
||||||
attrs[field_name] = getattr(instance, field_name)
|
attrs[field_name] = getattr(serializer.instance, field_name)
|
||||||
|
|
||||||
# Determine the filter keyword arguments and filter the queryset.
|
# Determine the filter keyword arguments and filter the queryset.
|
||||||
filter_kwargs = {
|
filter_kwargs = {
|
||||||
|
@ -141,13 +139,10 @@ class UniqueTogetherValidator:
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def __call__(self, attrs, serializer):
|
def __call__(self, attrs, serializer):
|
||||||
# Determine the existing instance, if this is an update operation.
|
self.enforce_required_fields(attrs, serializer)
|
||||||
instance = getattr(serializer, 'instance', None)
|
|
||||||
|
|
||||||
self.enforce_required_fields(attrs, instance)
|
|
||||||
queryset = self.queryset
|
queryset = self.queryset
|
||||||
queryset = self.filter_queryset(attrs, queryset, instance)
|
queryset = self.filter_queryset(attrs, queryset, serializer)
|
||||||
queryset = self.exclude_current_instance(attrs, queryset, instance)
|
queryset = self.exclude_current_instance(attrs, queryset, serializer.instance)
|
||||||
|
|
||||||
# Ignore validation if any field is None
|
# Ignore validation if any field is None
|
||||||
checked_values = [
|
checked_values = [
|
||||||
|
@ -207,13 +202,11 @@ class BaseUniqueForValidator:
|
||||||
# same as the serializer field names if `source=<>` is set.
|
# same as the serializer field names if `source=<>` is set.
|
||||||
field_name = serializer.fields[self.field].source_attrs[-1]
|
field_name = serializer.fields[self.field].source_attrs[-1]
|
||||||
date_field_name = serializer.fields[self.date_field].source_attrs[-1]
|
date_field_name = serializer.fields[self.date_field].source_attrs[-1]
|
||||||
# Determine the existing instance, if this is an update operation.
|
|
||||||
instance = getattr(serializer, 'instance', None)
|
|
||||||
|
|
||||||
self.enforce_required_fields(attrs)
|
self.enforce_required_fields(attrs)
|
||||||
queryset = self.queryset
|
queryset = self.queryset
|
||||||
queryset = self.filter_queryset(attrs, queryset, field_name, date_field_name)
|
queryset = self.filter_queryset(attrs, queryset, field_name, date_field_name)
|
||||||
queryset = self.exclude_current_instance(attrs, queryset, instance)
|
queryset = self.exclude_current_instance(attrs, queryset, serializer.instance)
|
||||||
if qs_exists(queryset):
|
if qs_exists(queryset):
|
||||||
message = self.message.format(date_field=self.date_field)
|
message = self.message.format(date_field=self.date_field)
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
|
|
|
@ -565,11 +565,10 @@ class TestCreateOnlyDefault:
|
||||||
on the callable if possible
|
on the callable if possible
|
||||||
"""
|
"""
|
||||||
class TestCallableDefault:
|
class TestCallableDefault:
|
||||||
def set_context(self, serializer_field):
|
requires_context = True
|
||||||
self.field = serializer_field
|
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self, field=None):
|
||||||
return "success" if hasattr(self, 'field') else "failure"
|
return "success" if field is not None else "failure"
|
||||||
|
|
||||||
class TestSerializer(serializers.Serializer):
|
class TestSerializer(serializers.Serializer):
|
||||||
context_set = serializers.CharField(default=serializers.CreateOnlyDefault(TestCallableDefault()))
|
context_set = serializers.CharField(default=serializers.CreateOnlyDefault(TestCallableDefault()))
|
||||||
|
|
|
@ -357,11 +357,16 @@ class TestUniquenessTogetherValidation(TestCase):
|
||||||
def filter(self, **kwargs):
|
def filter(self, **kwargs):
|
||||||
self.called_with = kwargs
|
self.called_with = kwargs
|
||||||
|
|
||||||
|
class MockSerializer:
|
||||||
|
def __init__(self, instance):
|
||||||
|
self.instance = instance
|
||||||
|
|
||||||
data = {'race_name': 'bar'}
|
data = {'race_name': 'bar'}
|
||||||
queryset = MockQueryset()
|
queryset = MockQueryset()
|
||||||
|
serializer = MockSerializer(instance=self.instance)
|
||||||
validator = UniqueTogetherValidator(queryset, fields=('race_name',
|
validator = UniqueTogetherValidator(queryset, fields=('race_name',
|
||||||
'position'))
|
'position'))
|
||||||
validator.filter_queryset(attrs=data, queryset=queryset, instance=self.instance)
|
validator.filter_queryset(attrs=data, queryset=queryset, serializer=serializer)
|
||||||
assert queryset.called_with == {'race_name': 'bar', 'position': 1}
|
assert queryset.called_with == {'race_name': 'bar', 'position': 1}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user