Skip to content
This repository has been archived by the owner on Jan 29, 2022. It is now read-only.

Rework FolderSerializer to use native DRF validation #130

Merged
merged 8 commits into from
Jan 31, 2021

Conversation

brianhelba
Copy link
Collaborator

@brianhelba brianhelba commented Jan 30, 2021

FullCleanModelSerializer does not work properly with internally-set fields like tree, since the value is not available at the time of initial validation. Currently, it only works because tree has editable=False, so the Model-layer validator skips the field.

See this comment for more information on the problem.

This refactor also has the result of effectively removing the default of parent=None when creating a folder. This is probably a net benefit, as it forces API clients to be explicit when creating a new root folder.

Also:

  • Add tests for POSTing invalid Folder values
  • Test folder updates with a PATCH request

dkc/core/rest/folder.py Outdated Show resolved Hide resolved
dkc/core/rest/folder.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@zachmullen zachmullen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we expand the scope of this PR to deleting FullCleanModelSerializer altogether? Based on this PR and our discussion, it seems like we shouldn't be using it anywhere. I think the only other changes needed would be in rest/file.py.

FullCleanModelSerializer does not work properly with internally-set fields
like "tree", since the value is not available at the time of initial
validation. Currently, it only works because "tree" has "editable=False",
so the Model-layer validator skips the field.

This refactor also has the result of effectively removing the default of
"parent=None" when creating a folder. This is probably a net benefit, as it
forces API clients to be explicit when creating a new root folder.
fields=['name'],
message='Root folders must have a unique name.',
),
# folder_max_depth and unique_root_folder_per_tree are internal sanity constraints,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, folder_max_depth is something we might want to check at the REST layer (rather than allowing the database to do it). I'm not sure how to do this, so I'll probably file a bug for a future fix if nobody else has suggestions.


def get_access(self, folder: Folder) -> Dict[str, bool]:
return folder.tree.get_access(self.context.get('user'))


class FolderUpdateSerializer(FolderSerializer):
class Meta(FolderSerializer.Meta):
fields = ['id', 'name', 'description']
read_only_fields = ['parent']
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specifying fields had the result of also limiting the output of what this serializer produced in the response to a PUT/PATCH request. What we really want to do is ensure that 'parent' cannot be changed in an update request, which this now does.

dkc/core/rest/folder.py Show resolved Hide resolved
dkc/core/rest/folder.py Show resolved Hide resolved
@@ -51,7 +95,7 @@ def test_folder_rest_retrieve(admin_api_client, folder):

@pytest.mark.django_db
def test_folder_rest_update(admin_api_client, folder):
resp = admin_api_client.put(
resp = admin_api_client.patch(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to outright disallow PUT requests at some point, but since I think we typically expect clients to use PATCH requests, it's better for this test to use that.

@brianhelba
Copy link
Collaborator Author

@zachmullen I intend to submit a second PR to remove FullCleanModelSerializer entirely, but it's going to be more manageable to refactor FileSerializer separately.

@brianhelba brianhelba requested a review from jbeezley January 30, 2021 23:32
@brianhelba
Copy link
Collaborator Author

Tests are failing due to kitware-resonant/django-composed-configuration#114 . They'll pass as soon as that's released.

Copy link
Collaborator

@zachmullen zachmullen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this change, the error response has the form:

{
  "non_field_errors": [
    "..."
  ]
}

I think we should associate these UniqueTogetherValidators with the name field, as that will be more consumable downstream. (Is that difficult to do?)

@brianhelba
Copy link
Collaborator Author

After this change, the error response has the form:

{
  "non_field_errors": [
    "..."
  ]
}

I think we should associate these UniqueTogetherValidators with the name field, as that will be more consumable downstream. (Is that difficult to do?)

For the case of sibling files, this is easy, as we just need to explicitly raise ValidationError({'name': ...}), and DRF will skip nesting it under NON_FIELD_ERRORS_KEY.

In the cases where UniqueTogetherValidator is used, setting message to be a dict instead of a string causes an error, as DRF calls .format on the message value. I've created a FormattableDict to wrap the values as a workaround.

@brianhelba brianhelba changed the title @brianhelba Rework FolderSerializer to use native DRF validation Rework FolderSerializer to use native DRF validation Jan 31, 2021
@brianhelba brianhelba requested a review from zachmullen January 31, 2021 01:28
@zachmullen
Copy link
Collaborator

Let's open that ticket for validating max depth.

@brianhelba
Copy link
Collaborator Author

Pushed 2 more minor commits.

@brianhelba
Copy link
Collaborator Author

As a note, following the advice to print(repr(FolderSerializer())) from https://www.django-rest-framework.org/api-guide/validators/#validation-in-rest-framework was quite helpful. Given how much of ModelSerializer subclasses are auto-generated, future development should always include this as an essential sanity check.

@brianhelba brianhelba merged commit 3fb2b9a into master Jan 31, 2021
@brianhelba brianhelba deleted the folder-serializer branch January 31, 2021 04:00
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants