incorect behavior when validating a list
abtinmo opened this issue · comments
when DRF throws ValidationError for elements inside of a list, package populates code and detail fields with not usable data.
example:
models:
class Day(models.Model):
name = models.CharField(max_length=50)
class Time(models.Model):
day = models.ForeignKey(Day, on_delete=models.CASCADE, related_name="times")
time = models.TimeField()
serializers
class TimeSerializer(serializers.ModelSerializer):
day = serializers.IntegerField(required=False)
class Meta:
fields = "__all__"
model = Time
class DaySerializer(serializers.ModelSerializer):
times = TimeSerializer(many=True)
class Meta:
fields = "__all__"
model = Day
def create(self, validated_data):
# handle nested creation
# . . .
request body:
{
"times": [{}],
"name": ""
}
response:
{
"type": "validation_error",
"code": "{'time': ['required']}",
"detail": "{'time': [ErrorDetail(string='This field is required.', code='required')]}",
"attr": "times"
}
list response
{
"type": "multiple",
"code": "multiple",
"detail": "Multiple exceptions ocurred. Please check list for details.",
"attr": null,
"list": [
{
"type": "validation_error",
"code": "{'time': ['required']}",
"detail": "{'time': [ErrorDetail(string='This field is required.', code='required')]}",
"attr": "times"
},
{
"type": "validation_error",
"code": "blank",
"detail": "This field may not be blank.",
"attr": "name"
}
]
I'm having the same problem.
Error is generated when value
is not a string on
drf-exceptions-hog/exceptions_hog/handler.py
Lines 167 to 172 in affa0e4
An extremely naive solution to part of the problem:
# Handle nested attributes
if isinstance(exception_key, list):
for key in exception_key:
value = value[key]
if isinstance(value, list):
for item in value:
value = item
if isinstance(value, dict):
for key in value:
value = value[key]
return str(value if isinstance(value, str) else value[0])
I think its related to this issue and This error started to occur in some of the plugins we use
How to fix this situation?
Error Trace
ValueError: not enough values to unpack (expected 2, got 1)
File "jwt/api_jws.py", line 191, in _load
header_segment, payload_segment = signing_input.split(b".", 1)
DecodeError: Not enough segments
File "rest_framework_simplejwt/backends.py", line 90, in decode
return jwt.decode(
File "jwt/api_jwt.py", line 119, in decode
decoded = self.decode_complete(jwt, key, algorithms, options, **kwargs)
File "jwt/api_jwt.py", line 90, in decode_complete
decoded = api_jws.decode_complete(
File "jwt/api_jws.py", line 149, in decode_complete
payload, signing_input, header, signature = self._load(jwt)
File "jwt/api_jws.py", line 193, in _load
raise DecodeError("Not enough segments") from err
TokenBackendError: Token is invalid or expired
File "rest_framework_simplejwt/tokens.py", line 43, in __init__
self.payload = token_backend.decode(token, verify=verify)
File "rest_framework_simplejwt/backends.py", line 105, in decode
raise TokenBackendError(_('Token is invalid or expired'))
TokenError: Token is invalid or expired
File "rest_framework_simplejwt/views.py", line 27, in post
serializer.is_valid(raise_exception=True)
File "rest_framework/serializers.py", line 227, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "rest_framework/serializers.py", line 429, in run_validation
value = self.validate(value)
File "rest_framework_simplejwt/serializers.py", line 104, in validate
refresh = RefreshToken(attrs['refresh'])
File "rest_framework_simplejwt/tokens.py", line 45, in __init__
raise TokenError(_('Token is invalid or expired'))
InvalidToken: {'detail': ErrorDetail(string='Token is invalid or expired', code='token_not_valid'), 'code': ErrorDetail(string='token_not_valid', code='token_not_valid')}
File "rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "rest_framework_simplejwt/views.py", line 29, in post
raise InvalidToken(e.args[0])
KeyError: 0
File "django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "contextlib.py", line 79, in inner
return func(*args, **kwds)
File "django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "rest_framework/views.py", line 466, in handle_exception
response = exception_handler(exc, context)
File "exceptions_hog/handler.py", line 295, in exception_handler
detail=_get_detail(exc, exception_list[0][1]),
File "exceptions_hog/utils.py", line 9, in function_wrapper
return_value: Any = func(*args, **kwargs)
File "exceptions_hog/handler.py", line 172, in _get_detail
return str(value if isinstance(value, str) else value[0])
Hey @abtinmo @luzfcb @mertcangokgoz, I attempted to solve this in #29. Added a test case for what you described above, but tests seem to pass as expected. I'm probably missing something on how your exceptions are being thrown. It would be a great help if you could write a test case on test_handler.py
to simulate the exact conditions that are leading to the exception, and I can then fix the code to get tests passing.
Alternatively, if you can take a look at #29 and let me know if I'm missing something related to the test case.
@paolodamico thank you for your support.
I'll do another test tomorrow about the problem, I don't think so, but there may be a problem in the code we developed. This problem may be caused by https://github.com/jazzband/djangorestframework-simplejwt, which we use for user logins on django.
If you want to test it, please do a little test with https://github.com/jazzband/djangorestframework-simplejwt.