Skip to content
Prev Previous commit
Next Next commit
Style cleanup
  • Loading branch information
lovelydinosaur committed Sep 30, 2016
commit 9ba36c23bbcfc2d5aa31cf27a61b82be42e16ea7
96 changes: 52 additions & 44 deletions rest_framework/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ def insert_into(target, keys, value):
target[keys[-1]] = value


def is_custom_action(action):
return action not in set([
'read', 'retrieve', 'list',
'create', 'update', 'partial_update', 'delete', 'destroy'
])


class EndpointInspector(object):
"""
A class to determine the available API endpoints that a project exposes.
Expand Down Expand Up @@ -133,6 +140,19 @@ def get_allowed_methods(self, callback):


class SchemaGenerator(object):
# Map methods onto 'actions' that are the names used in the link layout.
default_mapping = {
'get': 'read',
'post': 'create',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy',
}
# Coerce the following viewset actions into different names.
coerce_actions = {
'retrieve': 'read',
'destroy': 'delete'
}
endpoint_inspector_cls = EndpointInspector

def __init__(self, title=None, url=None, patterns=None, urlconf=None):
Expand Down Expand Up @@ -206,6 +226,20 @@ def has_view_permissions(self, view):
return False
return True

def is_list_endpoint(self, path, method, view):
"""
Return True if the given path/method appears to represent a list endpoint.
"""
if hasattr(view, 'action'):
return view.action == 'list'

if method.lower() != 'get':
return False
path_components = path.strip('/').split('/')
if path_components and '{' in path_components[-1]:
return False
return True

# Methods for generating each individual `Link` instance...

def get_link(self, path, method, view):
Expand Down Expand Up @@ -303,10 +337,7 @@ def get_serializer_fields(self, path, method, view):
return fields

def get_pagination_fields(self, path, method, view):
if method != 'GET':
return []

if getattr(view, 'action', 'list') != 'list':
if not self.is_list_endpoint(path, method, view):
return []

if not getattr(view, 'pagination_class', None):
Expand All @@ -316,10 +347,7 @@ def get_pagination_fields(self, path, method, view):
return as_query_fields(paginator.get_fields(view))

def get_filter_fields(self, path, method, view):
if method != 'GET':
return []

if getattr(view, 'action', 'list') != 'list':
if not self.is_list_endpoint(path, method, view):
return []

if not hasattr(view, 'filter_backends'):
Expand All @@ -330,22 +358,7 @@ def get_filter_fields(self, path, method, view):
fields += as_query_fields(filter_backend().get_fields(view))
return fields

# Methods for generating the link layout....

default_mapping = {
'get': 'read',
'post': 'create',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy',
}
coerce_actions = {
'retrieve': 'read',
'destroy': 'delete'
}
known_actions = set([
'create', 'read', 'list', 'update', 'partial_update', 'delete'
])
# Method for generating the link layout....

def get_keys(self, path, method, view):
"""
Expand All @@ -359,35 +372,30 @@ def get_keys(self, path, method, view):
/users/{pk}/groups/ ("groups", "list"), ("groups", "create")
/users/{pk}/groups/{pk}/ ("groups", "read"), ("groups", "update"), ("groups", "delete")
"""
path_components = path.strip('/').split('/')
named_path_components = [
component for component in path_components
if '{' not in component
]

if hasattr(view, 'action'):
# Viewsets have explicitly named actions.
action = view.action
# The default views use some naming that isn't well suited to what
# we'd actually like for the schema representation.
if action in self.coerce_actions:
action = self.coerce_actions[action]
if view.action in self.coerce_actions:
action = self.coerce_actions[view.action]
else:
action = view.action
else:
# Views have no associated action, so we determine one from the method.
method = method.lower()
if method == 'get':
is_detail = path_components and ('{' in path_components[-1])
action = 'read' if is_detail else 'list'
if self.is_list_endpoint(path, method, view):
action = 'list'
else:
action = self.default_mapping[method]
action = self.default_mapping[method.lower()]

if action in self.known_actions:
# Default action, eg "/users/", "/users/{pk}/"
idx = -1
else:
if is_custom_action(action):
# Custom action, eg "/users/{pk}/activate/", "/users/active/"
idx = -2
else:
# Default action, eg "/users/", "/users/{pk}/"
idx = -1

path_components = path.strip('/').split('/')
named_path_components = [
component for component in path_components if '{' not in component
]
try:
return (named_path_components[idx], action)
except IndexError:
Expand Down