feat(api/2): Show all available fields by default

This commit is contained in:
Karl Hobley 2015-10-08 22:30:04 +01:00
parent 4fb09ad7ca
commit 30ec65fc13
5 changed files with 39 additions and 37 deletions

View file

@ -81,7 +81,7 @@ class BaseAPIEndpoint(GenericViewSet):
return Response(data, status=status.HTTP_400_BAD_REQUEST)
return super(BaseAPIEndpoint, self).handle_exception(exc)
def get_api_fields(self, model):
def get_available_fields(self, model):
"""
This returns a list of field names that are allowed to
be used in the API (excluding the id field).
@ -100,7 +100,7 @@ class BaseAPIEndpoint(GenericViewSet):
query_parameters = set(self.request.GET.keys())
# All query paramters must be either a field or an operation
allowed_query_parameters = set(self.get_api_fields(queryset.model)).union(self.known_query_parameters).union({'id'})
allowed_query_parameters = set(self.get_available_fields(queryset.model)).union(self.known_query_parameters).union({'id'})
unknown_parameters = query_parameters - allowed_query_parameters
if unknown_parameters:
raise BadRequestError("query parameter is not an operation or a recognised field: %s" % ', '.join(sorted(unknown_parameters)))
@ -115,15 +115,17 @@ class BaseAPIEndpoint(GenericViewSet):
model = type(self.get_object())
# Get all available fields
all_fields = self.get_api_fields(model)
all_fields = list(OrderedDict.fromkeys(all_fields)) # Removes any duplicates in case the developer put "title" in api_fields
all_fields = self.get_available_fields(model)
# Remove any duplicates
all_fields = list(OrderedDict.fromkeys(all_fields))
if self.action == 'listing_view':
# Listing views just show the title field and any other allowed field the user specified
if 'fields' in request.GET:
fields = set(request.GET['fields'].split(','))
else:
fields = {'title'}
fields = set(all_fields)
unknown_fields = fields - set(all_fields)

View file

@ -16,7 +16,7 @@ class FieldsFilter(BaseFilterBackend):
This performs field level filtering on the result set
Eg: ?title=James Joyce
"""
fields = set(view.get_api_fields(queryset.model)).union({'id'})
fields = set(view.get_available_fields(queryset.model)).union({'id'})
for field_name, value in request.GET.items():
if field_name in fields:
@ -71,7 +71,7 @@ class OrderingFilter(BaseFilterBackend):
reverse_order = False
# Add ordering
if order_by == 'id' or order_by in view.get_api_fields(queryset.model):
if order_by == 'id' or order_by in view.get_available_fields(queryset.model):
queryset = queryset.order_by(order_by)
else:
# Unknown field

View file

@ -56,37 +56,37 @@ class TestDocumentListing(TestCase):
self.assertTrue(document['meta']['download_url'].startswith('http://localhost/documents/%d/' % document['id']))
# EXTRA FIELDS
# FIELDS
def test_extra_fields_default(self):
def test_fields_default(self):
response = self.get_response()
content = json.loads(response.content.decode('UTF-8'))
for document in content['results']:
self.assertEqual(set(document.keys()), {'id', 'meta', 'title'})
def test_extra_fields(self):
response = self.get_response(fields='title,tags')
content = json.loads(response.content.decode('UTF-8'))
for document in content['results']:
self.assertEqual(set(document.keys()), {'id', 'meta', 'title', 'tags'})
def test_extra_fields_tags(self):
def test_fields(self):
response = self.get_response(fields='title')
content = json.loads(response.content.decode('UTF-8'))
for document in content['results']:
self.assertEqual(set(document.keys()), {'id', 'meta', 'title'})
def test_fields_tags(self):
response = self.get_response(fields='tags')
content = json.loads(response.content.decode('UTF-8'))
for document in content['results']:
self.assertIsInstance(document['tags'], list)
def test_extra_fields_which_are_not_in_api_fields_gives_error(self):
def test_fields_which_are_not_in_api_fields_gives_error(self):
response = self.get_response(fields='uploaded_by_user')
content = json.loads(response.content.decode('UTF-8'))
self.assertEqual(response.status_code, 400)
self.assertEqual(content, {'message': "unknown fields: uploaded_by_user"})
def test_extra_fields_unknown_field_gives_error(self):
def test_fields_unknown_field_gives_error(self):
response = self.get_response(fields='123,title,abc')
content = json.loads(response.content.decode('UTF-8'))

View file

@ -53,23 +53,23 @@ class TestImageListing(TestCase):
self.assertEqual(image['meta']['detail_url'], 'http://localhost/api/v2beta/images/%d/' % image['id'])
# EXTRA FIELDS
# FIELDS
def test_extra_fields_default(self):
def test_fields_default(self):
response = self.get_response()
content = json.loads(response.content.decode('UTF-8'))
for image in content['results']:
self.assertEqual(set(image.keys()), {'id', 'meta', 'title'})
self.assertEqual(set(image.keys()), {'id', 'meta', 'title', 'width', 'height', 'tags'})
def test_extra_fields(self):
def test_fields(self):
response = self.get_response(fields='title,width,height')
content = json.loads(response.content.decode('UTF-8'))
for image in content['results']:
self.assertEqual(set(image.keys()), {'id', 'meta', 'title', 'width', 'height'})
def test_extra_fields_tags(self):
def test_fields_tags(self):
response = self.get_response(fields='tags')
content = json.loads(response.content.decode('UTF-8'))
@ -77,14 +77,14 @@ class TestImageListing(TestCase):
self.assertEqual(set(image.keys()), {'id', 'meta', 'tags'})
self.assertIsInstance(image['tags'], list)
def test_extra_fields_which_are_not_in_api_fields_gives_error(self):
def test_fields_which_are_not_in_api_fields_gives_error(self):
response = self.get_response(fields='uploaded_by_user')
content = json.loads(response.content.decode('UTF-8'))
self.assertEqual(response.status_code, 400)
self.assertEqual(content, {'message': "unknown fields: uploaded_by_user"})
def test_extra_fields_unknown_field_gives_error(self):
def test_fields_unknown_field_gives_error(self):
response = self.get_response(fields='123,title,abc')
content = json.loads(response.content.decode('UTF-8'))

View file

@ -109,23 +109,23 @@ class TestPageListing(TestCase):
self.assertEqual(response.status_code, 400)
self.assertEqual(content, {'message': "type doesn't exist"})
# EXTRA FIELDS
# FIELDS
def test_extra_fields_default(self):
def test_fields_default(self):
response = self.get_response(type='demosite.BlogEntryPage')
content = json.loads(response.content.decode('UTF-8'))
for page in content['results']:
self.assertEqual(set(page.keys()), {'id', 'meta', 'title'})
self.assertEqual(set(page.keys()), {'id', 'meta', 'title', 'date', 'related_links', 'feed_image', 'body', 'carousel_items', 'tags'})
def test_extra_fields(self):
def test_fields(self):
response = self.get_response(type='demosite.BlogEntryPage', fields='title,date,feed_image')
content = json.loads(response.content.decode('UTF-8'))
for page in content['results']:
self.assertEqual(set(page.keys()), {'id', 'meta', 'title', 'date', 'feed_image'})
def test_extra_fields_child_relation(self):
def test_fields_child_relation(self):
response = self.get_response(type='demosite.BlogEntryPage', fields='title,related_links')
content = json.loads(response.content.decode('UTF-8'))
@ -133,7 +133,7 @@ class TestPageListing(TestCase):
self.assertEqual(set(page.keys()), {'id', 'meta', 'title', 'related_links'})
self.assertIsInstance(page['related_links'], list)
def test_extra_fields_foreign_key(self):
def test_fields_foreign_key(self):
response = self.get_response(type='demosite.BlogEntryPage', fields='title,date,feed_image')
content = json.loads(response.content.decode('UTF-8'))
@ -149,7 +149,7 @@ class TestPageListing(TestCase):
self.assertEqual(feed_image['meta']['type'], 'wagtailimages.Image')
self.assertEqual(feed_image['meta']['detail_url'], 'http://localhost/api/v2beta/images/%d/' % feed_image['id'])
def test_extra_fields_tags(self):
def test_fields_tags(self):
response = self.get_response(type='demosite.BlogEntryPage', fields='tags')
content = json.loads(response.content.decode('UTF-8'))
@ -157,7 +157,7 @@ class TestPageListing(TestCase):
self.assertEqual(set(page.keys()), {'id', 'meta', 'tags'})
self.assertIsInstance(page['tags'], list)
def test_extra_field_ordering(self):
def test_fields_ordering(self):
response = self.get_response(type='demosite.BlogEntryPage', fields='date,title,feed_image,related_links')
# Will crash if the JSON is invalid
@ -175,21 +175,21 @@ class TestPageListing(TestCase):
]
self.assertEqual(list(content['results'][0].keys()), field_order)
def test_extra_fields_without_type_gives_error(self):
def test_fields_without_type_gives_error(self):
response = self.get_response(fields='title,related_links')
content = json.loads(response.content.decode('UTF-8'))
self.assertEqual(response.status_code, 400)
self.assertEqual(content, {'message': "unknown fields: related_links"})
def test_extra_fields_which_are_not_in_api_fields_gives_error(self):
def test_fields_which_are_not_in_api_fields_gives_error(self):
response = self.get_response(fields='path')
content = json.loads(response.content.decode('UTF-8'))
self.assertEqual(response.status_code, 400)
self.assertEqual(content, {'message': "unknown fields: path"})
def test_extra_fields_unknown_field_gives_error(self):
def test_fields_unknown_field_gives_error(self):
response = self.get_response(fields='123,title,abc')
content = json.loads(response.content.decode('UTF-8'))