Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7k
Handle Django's ValidationErrors in ListField#6423
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
carltongibson left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Right, hi,@sigvef.
Can you add test cases for each of the new behaviours you're looking to add here.
Really I'm thinking there's two things going on, so two PRs.
Just catchingDjangoValidationErrors here isn't I think something we'd go for.
(This has a long history.)
sigvef commentedJan 28, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Hi! Thanks for taking a look so quickly. I split out the first commit into a separate pull request:#6424 As the the DjangoValidationError change, I'd be happy to read up on some previous discussions. If you have any links laying about I'd be grateful :) |
carltongibson commentedFeb 14, 2019
4c68042 to04883beComparesigvef commentedFeb 14, 2019
I've updated this pull request accordingly. I'll add some tests if this change seems reasonable. |
sigvef commentedFeb 14, 2019
Some additional context on what this does: We have a Serializer that uses ListField like this: classSomeSerializer(serializers.Serializer):uuids=serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=Model.objects.something(),validators=[SomeCustomValidator()])) Validating data that looks like this works fine: {uuids: ['some-valid-uuid','some-valid-uuid']}Raising a DRF ValidationError for one of the children works fine, giving an error object like: {'uuids': {0:ErrorDetail(string='Some validation error')}}Raising a Django ValidationError for one of the children works differently (which serializers.PrimaryKeyRelatedField can do in some cases, like when the uuid is malformed). It gives an error object like: ["'X' is not a valid UUID."]Handling Django's ValidationErrors in ListField explicitly (like in this pull request), will maintain a regular error interface in this case: {'uuids': {0:ErrorDetail(string="'X' is not a valid UUID.")}} |
rpkilby commentedFeb 21, 2019
Sounds reasonable enough to me? Would need to verify the results with test cases.@carltongibson? |
carltongibson commentedFeb 21, 2019
Hey@rpkilby. Just haven't had a chance to think this through yet. Very happy for you to advise. 😀 |
rpkilby commentedFeb 21, 2019
Yeah - I would go ahead and write tests for this. You may want to parameterize the tests against both Django and DRF validation errors to ensure both are handled the same. |
kevin-brown left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Still seems reasonable, but I agree with having tests before accepting this.
smithdc1 commentedSep 7, 2020
Hi All Appreciate it's been a while and therefore don't expect anyone to recall this. I tried to write tests for this patch, but I must be miss-understanding this change. The As an example, the tests below raise a +classTestListDjangoValidation(FieldValues):+valid_inputs= [+ ]+invalid_inputs= [+ ([1,2], {0: [ErrorDetail(string='A Django Validation Error',code='invalid')],+1: [ErrorDetail(string='A Django Validation Error',code='invalid')]})]++outputs= [+ ]++defvalidate(value):+raiseDjangoValidationError('A Django Validation Error')++field=serializers.ListField(child=serializers.IntegerField(validators=[validate]))+classTestNestedListFieldDjangoValidators(FieldValues):+valid_inputs= [+ ]+invalid_inputs= [+ (+ [[1], [2]],+ {+0: [ErrorDetail(string='A Django Validation Error',code='invalid')],+1: [ErrorDetail(string='A Django Validation Error',code='invalid')],+ },+ ),+ ]+outputs= [+ ]++defvalidate(value):+raiseDjangoValidationError(ADjangoValidationError')++field=serializers.ListField(child=serializers.ListField(child=serializers.IntegerField(),validators=[validate])) |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
04883be tocea9527Comparesigvef commentedSep 22, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
If anyone is still interested in this: turns out that the PrimaryKeyRelatedField + UUID pk combination was important to reproduce the issue. I've updated the commit with a test case that fails without the proposed change. An alternative solution to the same testcase could perhaps be to add a corresponding change inside PrimaryKeyRelatedField instead. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
auvipy left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I will review myself and check if anything else is needed. in the mean time it would be great if you rebase this again on top of master branch
a5a3669 to6d6900dComparesigvef commentedDec 3, 2022
Great! Rebased! |
auvipy commentedDec 3, 2022
can you confirm you addressed this concern? |
Without this, Django's ValidationErrors will bypass the error collectionfrom ListField's children.Here is an example that illustrates this change.Consider a Serializer that uses ListField like this:```pythonclass SomeSerializer(serializers.Serializer): uuids = serializers.ListField(child=serializers.PrimaryKeyRelatedField( queryset=Model.objects.something(), validators=[SomeCustomValidator()]) )```Validating data that looks like this works fine:```python{uuids: ['some-valid-uuid', 'some-valid-uuid']}```Raising a DRF ValidationError for one of the children works fine, givingan error object like:```python{'uuids': {0: ErrorDetail(string='Some validation error')}}```Raising a Django ValidationError for one of the children worksdifferently (which serializers.PrimaryKeyRelatedField can do in somecases, like when the uuid is malformed). It gives an error object like:```python{'uuids': ["'X' is not a valid UUID."]}```Handling Django's ValidationErrors in ListField explicitly (like in thispull request), will maintain a regular error interface in this case:```python{'uuids': {0: ErrorDetail(string="'X' is not a valid UUID.")}}```6d6900d to6b66005Comparesigvef commentedDec 3, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Yeah. I had to do a little bit of spelunking in the code base to refresh my memory 😅, but here is an improved explanation. (incoming wall-of-text, sorry!) Most Django ValidationErrors are already properly handled by DRF. Django ValidationErrors raised during validation (i.e., inside a DRF Field's However, some Django ValidationErrors partially sneak past DRF's handling. DRF/Django can raise Django ValidationErrors from a DRF Field's How does that happen, specifically? Where does the Django ValidationError come from in the aforementioned case? It comes from line 262 (the django-rest-framework/rest_framework/relations.py Lines 255 to 266 incc3c89a
Within the Okay, what about DRF Serializer's "outer" exception handling? And why hasn't anyone else complained about this? DRF Serializer's exception handling in Quick reminder, what are we actually trying to fix? The goal is to fix a slight inconsistency in how certain error messages are structured in the API. The commit message/PR text contains an example of the difference -- although take heed, I've fixed a typo in the output that I discovered while typing up this comment. Mentioning it in case anyone has been following this thread for a while. How we fix this? The change in this PR is one way of solving this issue. It adds handling of Django ValidationErrors to DRF's ListField. Different options are also available:
I don't really have any particular preference for any which option. For what it's worth, at my day job we've been using a parallel reimplementation of DRF's |
auvipy commentedDec 4, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
thanks for your detail break downs. I think while we can accept this PR as minimal effort to fix the issue, the other two suggestion of overhaul also seems valid to me. can you open related PR or some failing tests two other suggestion you have in this Thread? |
auvipy commentedDec 4, 2022
Also if possible can you open source that implementation for the community? |
sigvef commentedDec 4, 2022
Taking a look at our parallel reimplementation, the parts that would maybe be interesting to the community would be covered by the changes in this PR and in#6424. |
sigvef commentedDec 4, 2022
As far as I can tell, the test added in this PR uncovers behaviour that each of the suggested fixes would sufficiently fix by itself. |
Uh oh!
There was an error while loading.Please reload this page.
Without this, Django's ValidationErrors will bypass the error collection
from ListField's children.
Here is an example that illustrates this change.
Consider a Serializer that uses ListField like this:
Validating data that looks like this works fine:
{uuids: ['some-valid-uuid','some-valid-uuid']}Raising a DRF ValidationError for one of the children works fine, giving
an error object like:
{'uuids': {0:ErrorDetail(string='Some validation error')}}Raising a Django ValidationError for one of the children works
differently (which serializers.PrimaryKeyRelatedField can do in some
cases, like when the uuid is malformed). It gives an error object like:
{'uuids': ["'X' is not a valid UUID."]}Handling Django's ValidationErrors in ListField explicitly (like in this
pull request), will maintain a regular error interface in this case:
{'uuids': {0:ErrorDetail(string="'X' is not a valid UUID.")}}