diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index b5aa78875..15e92ee72 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -1155,6 +1155,11 @@ The [html-json-forms][html-json-forms] package provides an algorithm and seriali [DRF-Base64][drf-base64] provides a set of field and model serializers that handles the upload of base64-encoded files. +## QueryFields + +[djangorestframework-queryfields][djangorestframework-queryfields] allows API clients to specify which fields will be sent in the response via inclusion or exclusion query paramaters. + + [cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion [relations]: relations.md [model-managers]: https://docs.djangoproject.com/en/stable/topics/db/managers/ @@ -1173,3 +1178,4 @@ The [html-json-forms][html-json-forms] package provides an algorithm and seriali [drf-dynamic-fields]: https://github.com/dbrgn/drf-dynamic-fields [drf-base64]: https://bitbucket.org/levit_scs/drf_base64 [drf-serializer-extensions]: https://github.com/evenicoulddoit/django-rest-framework-serializer-extensions +[djangorestframework-queryfields]: http://djangorestframework-queryfields.readthedocs.io/ diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md index 25ab4fd5b..f09788f56 100644 --- a/docs/topics/3.0-announcement.md +++ b/docs/topics/3.0-announcement.md @@ -894,11 +894,11 @@ If the request is omitted from the context, the returned URLs will be of the for The custom `X-Throttle-Wait-Second` header has now been dropped in favor of the standard `Retry-After` header. You can revert this behavior if needed by writing a custom exception handler for your application. -#### Date and time objects as ISO-8859-1 strings in serializer data. +#### Date and time objects as ISO-8601 strings in serializer data. Date and Time objects are now coerced to strings by default in the serializer output. Previously they were returned as `Date`, `Time` and `DateTime` objects, and later coerced to strings by the renderer. -You can modify this behavior globally by settings the existing `DATE_FORMAT`, `DATETIME_FORMAT` and `TIME_FORMAT` settings keys. Setting these values to `None` instead of their default value of `'iso-8859-1'` will result in native objects being returned in serializer data. +You can modify this behavior globally by settings the existing `DATE_FORMAT`, `DATETIME_FORMAT` and `TIME_FORMAT` settings keys. Setting these values to `None` instead of their default value of `'iso-8601'` will result in native objects being returned in serializer data. REST_FRAMEWORK = { # Return native `Date` and `Time` objects in `serializer.data` diff --git a/docs/topics/third-party-resources.md b/docs/topics/third-party-resources.md index 462bd922a..1ccedbc01 100644 --- a/docs/topics/third-party-resources.md +++ b/docs/topics/third-party-resources.md @@ -207,6 +207,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque * [html-json-forms][html-json-forms] - Provides an algorithm and serializer to process HTML JSON Form submissions per the (inactive) spec. * [django-rest-framework-serializer-extensions][drf-serializer-extensions] - Enables black/whitelisting fields, and conditionally expanding child serializers on a per-view/request basis. +* [djangorestframework-queryfields][djangorestframework-queryfields] - Serializer mixin allowing clients to control which fields will be sent in the API response. ### Serializer fields @@ -370,3 +371,4 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque [drf_tweaks]: https://github.com/ArabellaTech/drf_tweaks [drf-oidc-auth]: https://github.com/ByteInternet/drf-oidc-auth [drf-serializer-extensions]: https://github.com/evenicoulddoit/django-rest-framework-serializer-extensions +[djangorestframework-queryfields]: https://github.com/wimglenn/djangorestframework-queryfields diff --git a/docs/tutorial/1-serialization.md b/docs/tutorial/1-serialization.md index 04fb6914a..710dfb8e7 100644 --- a/docs/tutorial/1-serialization.md +++ b/docs/tutorial/1-serialization.md @@ -48,6 +48,8 @@ We'll need to add our new `snippets` app and the `rest_framework` app to `INSTAL 'snippets.apps.SnippetsConfig', ) +Please note that if you're using Django <1.9, you need to replace `snippets.apps.SnippetsConfig` with `snippets`. + Okay, we're ready to roll. ## Creating a model to work with diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py index 60d7f7097..3bb3f7897 100644 --- a/rest_framework/pagination.py +++ b/rest_framework/pagination.py @@ -294,7 +294,7 @@ class PageNumberPagination(BasePagination): name=self.page_query_param, required=False, location='query', - description=force_text(self.page_query_description) + #description=force_text(self.page_query_description) ) ] if self.page_size_query_param is not None: @@ -303,7 +303,7 @@ class PageNumberPagination(BasePagination): name=self.page_size_query_param, required=False, location='query', - description=force_text(self.page_size_query_description) + #description=force_text(self.page_size_query_description) ) ) return fields @@ -444,13 +444,13 @@ class LimitOffsetPagination(BasePagination): name=self.limit_query_param, required=False, location='query', - description=force_text(self.limit_query_description) + #description=force_text(self.limit_query_description) ), coreapi.Field( name=self.offset_query_param, required=False, location='query', - description=force_text(self.offset_query_description) + #description=force_text(self.offset_query_description) ) ] diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 97ec8164c..95ea3690c 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -798,10 +798,30 @@ class DocumentationRenderer(BaseRenderer): media_type = 'text/html' format = 'html' charset = 'utf-8' + template = 'rest_framework/docs/index.html' + code_style = 'emacs' + + def get_context(self, data): + from pygments.formatters import HtmlFormatter + from django.utils.html import mark_safe + formatter = HtmlFormatter(style=self.code_style) + code_style = formatter.get_style_defs('.highlight') + langs = ['shell', 'javascript', 'python'] + codec = coreapi.codecs.CoreJSONCodec() + schema = mark_safe(codec.encode(data)) + return { + 'document': data, + 'langs': langs, + 'code_style': code_style, + 'schema': schema + } def render(self, data, accepted_media_type=None, renderer_context=None): - from coredocs.main import render as render_docs - return render_docs(data, theme='cerulean', highlight='emacs', static=lambda path: '/static/rest_framework/docs/' + path) + #from coredocs.main import render as render_docs + #return render_docs(data, theme='cerulean', highlight='emacs', static=lambda path: '/static/rest_framework/docs/' + path) + template = loader.get_template(self.template) + context = self.get_context(data) + return template_render(template, context, request=renderer_context['request']) class MultiPartRenderer(BaseRenderer): diff --git a/rest_framework/schemas.py b/rest_framework/schemas.py index fb7d12985..3a35db2cc 100644 --- a/rest_framework/schemas.py +++ b/rest_framework/schemas.py @@ -514,8 +514,8 @@ class SchemaGenerator(object): name=variable, location='path', required=True, - title='' if (title is None) else title, - description='' if (description is None) else description + #title='' if (title is None) else title, + #description='' if (description is None) else description ) fields.append(field) @@ -540,7 +540,7 @@ class SchemaGenerator(object): name='data', location='body', required=True, - type='array' + #type='array' ) ] @@ -559,11 +559,11 @@ class SchemaGenerator(object): name=field.field_name, location='form', required=required, - title=title, - description=description, - type=types_lookup[field], - input=determine_input(field), - choices=getattr(field, 'choices', None) + #title=title, + #description=description, + #type=types_lookup[field], + #input=determine_input(field), + #choices=getattr(field, 'choices', None) ) fields.append(field) diff --git a/rest_framework/templates/rest_framework/docs/document.html b/rest_framework/templates/rest_framework/docs/document.html new file mode 100644 index 000000000..e7cde659e --- /dev/null +++ b/rest_framework/templates/rest_framework/docs/document.html @@ -0,0 +1,19 @@ +{% load rest_framework %} +
{% render_markdown document.description %}
+{% code bash %}# Load the schema document
+$ coreapi get {{ document.url }}{% if schema_format %} --format {{ schema_format }}{% endif %}
+
+# Interact with the API endpoint
+$ coreapi action {% if section_key %}{{ section_key }} {% endif %}{{ link_key }}{% for field in link.fields %} -p {{ field.name }}=...{% endfor %}{% endcode %}
diff --git a/rest_framework/templates/rest_framework/docs/link.html b/rest_framework/templates/rest_framework/docs/link.html
new file mode 100644
index 000000000..2d0f1879a
--- /dev/null
+++ b/rest_framework/templates/rest_framework/docs/link.html
@@ -0,0 +1,119 @@
+{% load rest_framework %}
+
+ {{ link.action|upper }} {{ link.url }}
+
{% render_markdown link.description %}
+ +{% if link.fields|with_location:'path' %} +The following parameters should be included in the URL path.
+Parameter | Description |
---|---|
{{ field.name }} {% if field.required %} required{% endif %} | {% if field.description %}{{ field.description }}{% endif %} |
The following parameters should be included as part of a URL query string.
+Parameter | Description |
---|---|
{{ field.name }} {% if field.required %} required{% endif %} | {% if field.description %}{{ field.description }}{% endif %} |
The following parameters should be included as HTTP headers.
+Parameter | Description |
---|---|
{{ field.name }} {% if field.required %} required{% endif %} | {% if field.description %}{{ field.description }}{% endif %} |
The request body should be "{{ link.encoding }}"
encoded, and should contain a single item.
Parameter | Description |
---|---|
{{ field.name }} {% if field.required %} required{% endif %} | {% if field.description %}{{ field.description }}{% endif %} |
The request body should be a "{{ link.encoding }}"
encoded object, containing the following items.
Parameter | Description |
---|---|
{{ field.name }} {% if field.required %} required{% endif %} | {% if field.description %}{{ field.description }}{% endif %} |
%s
'
+ LANG_TAG = ' class="highlight %s"'
+
+
+class FencedCodeExtension(markdown.Extension):
+
+ def extendMarkdown(self, md, md_globals):
+ """ Add FencedBlockPreprocessor to the Markdown instance. """
+ md.registerExtension(self)
+
+ md.preprocessors.add('fenced_code_block',
+ CustomFencedBlockPreprocessor(md),
+ ">normalize_whitespace")
+
+
+from pygments import highlight
+from pygments.lexers import get_lexer_by_name
+from pygments.formatters import HtmlFormatter
+
+
+@register.tag(name='code')
+def do_code(parser,token):
+ code = token.split_contents()[-1]
+ nodelist = parser.parse(('endcode',))
+ parser.delete_first_token()
+ return CodeNode(code, nodelist)
+
+
+class CodeNode(template.Node):
+ style = 'emacs'
+
+ def __init__(self, lang, code):
+ self.lang = lang
+ self.nodelist = code
+
+ def render(self, context):
+ body = self.nodelist.render(context)
+ lexer = get_lexer_by_name(self.lang, stripall=False)
+ formatter = HtmlFormatter(nowrap=True, style=self.style)
+ code = highlight(body, lexer, formatter)
+ return code
+
+
+@register.filter()
+def with_location(fields, location):
+ return [
+ field for field in fields
+ if field.location == location
+ ]
+
+
+@register.simple_tag
+def form_for_link(link):
+ import coreschema
+ properties = {
+ field.name: field.schema or coreschema.String()
+ for field in link.fields
+ }
+ required = [
+ field.name
+ for field in link.fields
+ if field.required
+ ]
+ schema = coreschema.Object(properties=properties, required=required)
+ return coreschema.render_to_form(schema)
+
+
+@register.simple_tag
+def render_markdown(markdown_text):
+ return markdown.markdown(markdown_text, extensions=[FencedCodeExtension(), "tables"])
+
+
@register.simple_tag
def get_pagination_html(pager):
return pager.to_html()