Compare commits

...

15 Commits

Author SHA1 Message Date
Cristi Vîjdea d2dc09cb3c Fix changelog markup 2018-04-25 23:04:43 +03:00
Cristi Vîjdea 36992072ca Add 1.6.2 changelog 2018-04-25 22:58:02 +03:00
Cristi Vîjdea aa90723703 Switch to redoc 2.0 alpha
Update redoc to 2.0.0-alpha.17
2018-04-25 22:55:25 +03:00
Cristi Vîjdea 301511bebc Update swagger-ui to 3.13.6 2018-04-25 22:44:49 +03:00
Cristi Vîjdea c0f37f6ec1 Avoid crash when hitting unknown model fields
Fixes #102
2018-04-25 22:41:06 +03:00
Tobias Krönke 5e684549a1 Correct values in swagger-ui docs (#108) 2018-04-25 17:53:22 +03:00
John Carter 322971f3e7 Make parameters order stable for multi-parameter URLs (#106)
Fixes #105

* Added intermittently failing test for #105
* Make parameter order stable for urls with multiple params
2018-04-23 19:16:22 +03:00
Cristi Vîjdea 6dd8ded05d Update swagger-ui to 3.13.3 2018-04-09 13:55:17 +03:00
Cristi Vîjdea 7270154828 Test with Django Rest Framework 3.8 (#96)
* Add djangorestframework 3.8 to tox and travis
* Add @action tests
* Limit tox to <3.0.0
2018-04-04 22:59:57 +03:00
Cristi Vîjdea 6f7d14fdb2 Add 1.6.1 changelog 2018-04-01 12:08:14 +03:00
shahha 941ec8fdaf Added SUPPORTED_SUBMIT_METHODS swagger ui setting (#91) 2018-03-26 11:15:28 +03:00
Cristi Vîjdea 51ec07261d Improve OAuth2 behaviour and documentation (#90)
* Set OAUTH2_REDIRECT_URL to oauth2-redirect.html by default
* Add example SWAGGER_SETTINGS for OAuth
* Add note about redirect URL
2018-03-24 13:05:37 +02:00
Cristi Vîjdea a9cdf6d561 Fix type of properties in Schema docstring
Fixes #87.
2018-03-21 13:39:14 +02:00
Cristi Vîjdea a64ce95e3c Reset testproj migrations
Heroku deployment issues...
2018-03-18 20:35:02 +02:00
Cristi Vîjdea c9147a5746 Fix testproj people app 2018-03-18 20:20:04 +02:00
42 changed files with 2666 additions and 325 deletions
+2
View File
@@ -159,3 +159,5 @@ com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
\.pytest_cache/
+2
View File
@@ -8,6 +8,7 @@
<option name="manageScript" value="manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="migrations" />
</configuration>
</facet>
</component>
@@ -15,6 +16,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/testproj" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/docs/_build" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.6 (drf-yasg)" jdkType="Python SDK" />
+2 -1
View File
@@ -10,11 +10,12 @@
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ourVersions">
<value>
<list size="4">
<list size="5">
<item index="0" class="java.lang.String" itemvalue="2.7" />
<item index="1" class="java.lang.String" itemvalue="3.4" />
<item index="2" class="java.lang.String" itemvalue="3.5" />
<item index="3" class="java.lang.String" itemvalue="3.6" />
<item index="4" class="java.lang.String" itemvalue="3.7" />
</list>
</value>
</option>
+3
View File
@@ -70,4 +70,7 @@
</LinkMapSettings>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (drf-yasg)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>
+1
View File
@@ -9,6 +9,7 @@ python:
env:
- DRF=3.7
- DRF=3.8
jobs:
include:
+1 -1
View File
@@ -11,7 +11,7 @@ Generate **real** Swagger/OpenAPI 2.0 specifications from a Django Rest Framewor
Compatible with
- **Django Rest Framework**: 3.7.7
- **Django Rest Framework**: 3.7.7, 3.8.x
- **Django**: 1.11.x, 2.0.x
- **Python**: 2.7, 3.4, 3.5, 3.6
+27
View File
@@ -3,6 +3,33 @@ Changelog
#########
*********
**1.6.2**
*********
*Release date: Apr 25, 2018*
- **IMPROVED:** updated ``swagger-ui`` to version 3.13.6
- **IMPROVED:** switched ``ReDoc`` to version 2.0.0-alpha.17 (was 1.21.2); fixes :issue:`107`
- **FIXED:** made documentation ordering of parameters stable for urls with multiple parameters (:issue:`105`, :pr:`106`)
- **FIXED:** fixed crash when using a model ``ChoiceField`` of unknown child type
*********
**1.6.1**
*********
*Release date: Apr 01, 2018*
- **ADDED:** added ``SUPPORTED_SUBMIT_METHODS`` ``swagger-ui`` setting
*********
**1.6.0**
*********
*Release date: Mar 24, 2018*
- **IMPROVED:** ``OAUTH2_REDIRECT_URL`` will now default to the built in ``oauth2-redirect.html`` file
*********
**1.5.1**
*********
+1 -1
View File
@@ -273,7 +273,7 @@ def role_github_user(name, rawtext, text, lineno, inliner, options=None, content
options = options or {}
content = content or []
if not re.match(r"^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$", text):
if not re.match(r"^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$", text, re.IGNORECASE):
return sphinx_err(inliner, lineno, rawtext, '"%s" is not a valid GitHub username.' % text)
ref = gh_user_uri.format(text)
+4 -4
View File
@@ -87,8 +87,8 @@ Where you can use the :func:`@swagger_auto_schema <.swagger_auto_schema>` decora
* for ``ViewSet``, ``GenericViewSet``, ``ModelViewSet``, because each viewset corresponds to multiple **paths**, you have
to decorate the *action methods*, i.e. ``list``, ``create``, ``retrieve``, etc. |br|
Additionally, ``@list_route``\ s or ``@detail_route``\ s defined on the viewset, like function based api views, can
respond to multiple HTTP methods and thus have multiple operations that must be decorated separately:
Additionally, ``@action``\ s, `@list_route``\ s or ``@detail_route``\ s defined on the viewset, like function based
api views, can respond to multiple HTTP methods and thus have multiple operations that must be decorated separately:
.. code-block:: python
@@ -96,13 +96,13 @@ Where you can use the :func:`@swagger_auto_schema <.swagger_auto_schema>` decora
class ArticleViewSet(viewsets.ModelViewSet):
# method or 'methods' can be skipped because the list_route only handles a single method (GET)
@swagger_auto_schema(operation_description='GET /articles/today/')
@list_route(methods=['get'])
@action(detail=False, methods=['get'])
def today(self, request):
...
@swagger_auto_schema(method='get', operation_description="GET /articles/{id}/image/")
@swagger_auto_schema(method='post', operation_description="POST /articles/{id}/image/")
@detail_route(methods=['get', 'post'], parser_classes=(MultiPartParser,))
@action(detail=True, methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, id=None):
...
+34
View File
@@ -63,3 +63,37 @@ settings described below were added as a result of discussion in issue :issue:`5
The settings of interest can be found on the :ref:`settings page <oauth2-settings>`. Configuration options are similar
to most OAuth client setups like web or mobile applications. Reading the relevant ``swagger-ui`` docmentation linked
will also probably help.
Example
^^^^^^^
A very simple working configuration was provided by :ghuser:`Vigrond`, originally at
`https://github.com/Vigrond/django_oauth2_example <https://github.com/Vigrond/django_oauth2_example>`_.
.. code-block:: python
SWAGGER_SETTINGS = {
'USE_SESSION_AUTH': False,
'SECURITY_DEFINITIONS': {
'Your App API - Swagger': {
'type': 'oauth2',
'authorizationUrl': '/yourapp/o/authorize',
'tokenUrl': '/yourapp/o/token/',
'flow": "accessCode',
'scopes': {
'read:groups': 'read groups',
}
}
},
'OAUTH2_CONFIG': {
'clientId': 'yourAppClientId',
'clientSecret': 'yourAppClientSecret',
'appName': 'your application name'
},
}
If the OAuth2 provider requires you to provide the full absolute redirect URL, the default value for most
``staticfiles`` configurations will be ``<origin>/static/drf-yasg/swagger-ui-dist/oauth2-redirect.html``. If this is
not suitable for some reason, you can override the ``OAUTH2_REDIRECT_URL`` setting as appropriate.
+21 -9
View File
@@ -190,8 +190,8 @@ OPERATIONS_SORTER
Sorting order for the operation list of each tag.
* :python:`None`: show in the order returned by the server
* :python:`alpha`: sort alphabetically by path
* :python:`method`: sort by HTTP method
* :python:`'alpha'`: sort alphabetically by path
* :python:`'method'`: sort by HTTP method
**Default**: :python:`None` |br|
*Maps to parameter*: ``operationsSorter``
@@ -202,7 +202,7 @@ TAGS_SORTER
Sorting order for tagged operation groups.
* :python:`None`: Swagger UI default ordering
* :python:`alpha`: sort alphabetically
* :python:`'alpha'`: sort alphabetically
**Default**: :python:`None` |br|
*Maps to parameter*: ``tagsSorter``
@@ -212,9 +212,9 @@ DOC_EXPANSION
Controls the default expansion setting for the operations and tags.
* :python:`None`: everything is collapsed
* :python:`list`: only tags are expanded
* :python:`full`: all operations are expanded
* :python:`'none'`: everything is collapsed
* :python:`'list'`: only tags are expanded
* :python:`'full'`: all operations are expanded
**Default**: :python:`'list'` |br|
*Maps to parameter*: ``docExpansion``
@@ -240,8 +240,8 @@ DEFAULT_MODEL_RENDERING
Controls whether operations show the model structure or the example value by default.
* :python:`model`: show the model fields by default
* :python:`example`: show the example value by default
* :python:`'model'`: show the model fields by default
* :python:`'example'`: show the example value by default
**Default**: :python:`'model'` |br|
*Maps to parameter*: ``defaultModelRendering``
@@ -259,7 +259,10 @@ Controls how many levels are expaned by default when showing nested models.
OAUTH2_REDIRECT_URL
-------------------
Used when OAuth2 authenitcation of API requests via swagger-ui is desired.
Used when OAuth2 authenitcation of API requests via swagger-ui is desired. If ``None`` is passed, the
``oauth2RedirectUrl`` parameter will be set to ``{% static 'drf-yasg/swagger-ui-dist/oauth2-redirect.html' %}``. This
is the default `https://github.com/swagger-api/swagger-ui/blob/master/dist/oauth2-redirect.html <oauth2-redirect>`_
file provided by ``swagger-ui``.
**Default**: :python:`None` |br|
*Maps to parameter*: ``oauth2RedirectUrl``
@@ -273,6 +276,15 @@ to the ``SwaggerUIBundle#initOAuth`` method, and must be a dictionary. See
**Default**: :python:`{}`
SUPPORTED_SUBMIT_METHODS
------------------------
List of HTTP methods that have the Try it out feature enabled. An empty array disables Try it out for all operations.
This does not filter the operations from the display.
**Default**: :python:`['get','put','post','delete','options','head','patch','trace']` |br|
*Maps to parameter*: ``supportedSubmitMethods``
******************
``REDOC_SETTINGS``
******************
+2261 -155
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,8 +1,8 @@
{
"name": "drf-yasg",
"dependencies": {
"redoc": "^1.21.2",
"swagger-ui-dist": "^3.13.0"
"redoc": "^2.0.0-alpha.17",
"swagger-ui-dist": "^3.13.6"
},
"repository": {
"type": "git",
+1 -1
View File
@@ -1,5 +1,5 @@
# requirements for building and running tox
tox>=2.9.1
tox>=2.9.1,<3.0.0
detox>=0.11
-r setup.txt
+10
View File
@@ -46,6 +46,16 @@ SWAGGER_DEFAULTS = {
'DEFAULT_MODEL_DEPTH': 3,
'OAUTH2_REDIRECT_URL': None,
'OAUTH2_CONFIG': {},
'SUPPORTED_SUBMIT_METHODS': [
'get',
'put',
'post',
'delete',
'options',
'head',
'patch',
'trace'
],
}
REDOC_DEFAULTS = {
+1 -1
View File
@@ -403,7 +403,7 @@ class OpenAPISchemaGenerator(object):
queryset = getattr(view_cls, 'queryset', None)
model = getattr(getattr(view_cls, 'queryset', None), 'model', None)
for variable in uritemplate.variables(path):
for variable in sorted(uritemplate.variables(path)):
model, model_field = get_queryset_field(queryset, variable)
attrs = get_basic_type_info(model_field) or {'type': openapi.TYPE_STRING}
if getattr(view_cls, 'lookup_field', None) == variable and attrs['type'] == openapi.TYPE_STRING:
+3 -1
View File
@@ -410,7 +410,9 @@ class ChoiceFieldInspector(FieldInspector):
model = getattr(getattr(serializer, 'Meta'), 'model')
model_field = get_model_field(model, field.source)
if model_field:
enum_type = get_basic_type_info(model_field).get('type', enum_type)
model_type = get_basic_type_info(model_field)
if model_type:
enum_type = model_type.get('type', enum_type)
if isinstance(field, serializers.MultipleChoiceField):
return SwaggerType(
+1 -1
View File
@@ -425,7 +425,7 @@ class Schema(SwaggerDict):
:param str format: value format, see OpenAPI spec
:param list enum: restrict possible values
:param str pattern: pattern if type is ``string``
:param list[.Schema,.SchemaRef] properties: object properties; required if `type` is ``object``
:param dict[str,(.Schema,.SchemaRef)] properties: object properties; required if `type` is ``object``
:param bool,.Schema,.SchemaRef additional_properties: allow wildcard properties not listed in `properties`
:param list[str] required: list of requried property names
:param .Schema,.SchemaRef items: type of array items, only valid if `type` is ``array``
+1
View File
@@ -94,6 +94,7 @@ class _UIRenderer(BaseRenderer):
'defaultModelExpandDepth': swagger_settings.DEFAULT_MODEL_DEPTH,
'defaultModelsExpandDepth': swagger_settings.DEFAULT_MODEL_DEPTH,
'oauth2RedirectUrl': swagger_settings.OAUTH2_REDIRECT_URL,
'supportedSubmitMethods': swagger_settings.SUPPORTED_SUBMIT_METHODS,
}
data = {k: v for k, v in data.items() if v is not None}
if swagger_settings.VALIDATOR_URL != '':
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -38,7 +38,7 @@ function initSwaggerUi() {
],
layout: "StandaloneLayout",
filter: true,
requestInterceptor: function(request) {
requestInterceptor: function (request) {
var headers = request.headers || {};
var csrftoken = document.querySelector("[name=csrfmiddlewaretoken]");
if (csrftoken) {
@@ -49,8 +49,15 @@ function initSwaggerUi() {
};
var swaggerSettings = JSON.parse(document.getElementById('swagger-settings').innerHTML);
console.log(swaggerSettings);
if (!('oauth2RedirectUrl' in swaggerSettings)) {
var oauth2RedirectUrl = document.getElementById('oauth2-redirect-url');
if (oauth2RedirectUrl) {
swaggerSettings['oauth2RedirectUrl'] = oauth2RedirectUrl.href;
oauth2RedirectUrl.parentNode.removeChild(oauth2RedirectUrl);
}
}
console.log(swaggerSettings);
for (var p in swaggerSettings) {
if (swaggerSettings.hasOwnProperty(p)) {
swaggerConfig[p] = swaggerSettings[p];
@@ -67,6 +67,8 @@
<script src="{% static 'drf-yasg/insQ.min.js' %}"></script>
<script src="{% static 'drf-yasg/swagger-ui-init.js' %}"></script>
<a id="oauth2-redirect-url" href="{% static 'drf-yasg/swagger-ui-dist/oauth2-redirect.html' %}" class="hidden"></a>
<div id="django-session-auth" class="hidden">
{% if USE_SESSION_AUTH %}
{% csrf_token %}
+9 -8
View File
@@ -114,7 +114,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
# no overrides to set, no use in doing more work
return
# if the method is a detail_route or list_route, it will have a bind_to_methods attribute
# if the method is an @action, it will have a bind_to_methods attribute
bind_to_methods = getattr(view_method, 'bind_to_methods', [])
# if the method is actually a function based view (@api_view), it will have a 'cls' attribute
view_cls = getattr(view_method, 'cls', None)
@@ -126,7 +126,7 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
_methods = methods
if methods or method:
assert available_methods or http_method_names, "`method` or `methods` can only be specified " \
"on @detail_route or @api_view views"
"on @action or @api_view views"
assert bool(methods) != bool(method), "specify either method or methods"
assert not isinstance(methods, str), "`methods` expects to receive a list of methods;" \
" use `method` for a single argument"
@@ -138,13 +138,13 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
assert not any(mth in existing_data for mth in _methods), "http method defined multiple times"
if available_methods:
# detail_route, list_route or api_view
# action or api_view
assert bool(http_method_names) != bool(bind_to_methods), "this should never happen"
if len(available_methods) > 1:
assert _methods, \
"on multi-method api_view, detail_route or list_route, you must specify swagger_auto_schema on " \
"a per-method basis using one of the `method` or `methods` arguments"
"on multi-method api_view, action, detail_route or list_route, you must specify " \
"swagger_auto_schema on a per-method basis using one of the `method` or `methods` arguments"
else:
# for a single-method view we assume that single method as the decorator target
_methods = _methods or available_methods
@@ -156,8 +156,9 @@ def swagger_auto_schema(method=None, methods=None, auto_schema=unset, request_bo
view_method._swagger_auto_schema = existing_data
else:
assert not _methods, \
"the methods argument should only be specified when decorating a detail_route or list_route; you " \
"should also ensure that you put the swagger_auto_schema decorator AFTER (above) the _route decorator"
"the methods argument should only be specified when decorating an action, detail_route or " \
"list_route; you should also ensure that you put the swagger_auto_schema decorator " \
"AFTER (above) the _route decorator"
assert not existing_data, "swagger_auto_schema applied twice to method"
view_method._swagger_auto_schema = data
@@ -183,7 +184,7 @@ def is_list_view(path, method, view):
return True
if action in ('retrieve', 'update', 'partial_update', 'destroy') or detail is True or suffix == 'Instance':
# a detail_route is surely not a list route
# a detail action is surely not a list route
return False
# for GenericAPIView, if it's a detail view it can't also be a list view
+22 -1
View File
@@ -1,8 +1,9 @@
# Generated by Django 2.0 on 2017-12-23 09:07
# Generated by Django 2.0.1 on 2018-03-18 18:32
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
@@ -23,8 +24,28 @@ class Migration(migrations.Migration):
('slug', models.SlugField(blank=True, help_text='slug model help_text', unique=True)),
('date_created', models.DateTimeField(auto_now_add=True)),
('date_modified', models.DateTimeField(auto_now=True)),
('article_type', models.PositiveSmallIntegerField(choices=[(1, 'first'), (2, 'second'), (3, 'third'), (7, 'seven'), (8, 'eight')], help_text='IntegerField declared on model with choices=(...) and exposed via ModelSerializer', null=True)),
('cover', models.ImageField(blank=True, upload_to='article/original/')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='articles', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='ArticleGroup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
('title', models.CharField(help_text='title model help_text', max_length=255, unique=True)),
('slug', models.SlugField(blank=True, help_text='slug model help_text', unique=True)),
],
),
migrations.AddField(
model_name='article',
name='group',
field=models.ForeignKey(blank=True, default=None, on_delete=django.db.models.deletion.PROTECT, related_name='articles_as_main', to='articles.ArticleGroup'),
),
migrations.AddField(
model_name='article',
name='original_group',
field=models.ForeignKey(blank=True, default=None, on_delete=django.db.models.deletion.PROTECT, related_name='articles_as_original', to='articles.ArticleGroup'),
),
]
@@ -1,18 +0,0 @@
# Generated by Django 2.0.1 on 2018-02-26 18:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('articles', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='article',
name='article_type',
field=models.PositiveSmallIntegerField(choices=[(1, 'first'), (2, 'second'), (3, 'third'), (7, 'seven'), (8, 'eight')], help_text='IntegerField declared on model with choices=(...) and exposed via ModelSerializer', null=True),
),
]
@@ -1,36 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-03-10 01:42
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('articles', '0002_article_article_type'),
]
operations = [
migrations.CreateModel(
name='ArticleGroup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
('title', models.CharField(help_text='title model help_text', max_length=255, unique=True)),
('slug', models.SlugField(blank=True, help_text='slug model help_text', unique=True)),
],
),
migrations.AddField(
model_name='article',
name='group',
field=models.ForeignKey(blank=True, default=None, on_delete=django.db.models.deletion.PROTECT, related_name='articles_as_main', to='articles.ArticleGroup'),
),
migrations.AddField(
model_name='article',
name='original_group',
field=models.ForeignKey(blank=True, default=None, on_delete=django.db.models.deletion.PROTECT, related_name='articles_as_original', to='articles.ArticleGroup'),
),
]
+42 -16
View File
@@ -3,6 +3,7 @@ import datetime
from django.utils.decorators import method_decorator
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
# noinspection PyDeprecation
from rest_framework.decorators import detail_route, list_route
from rest_framework.filters import OrderingFilter
from rest_framework.pagination import LimitOffsetPagination
@@ -89,23 +90,48 @@ class ArticleViewSet(viewsets.ModelViewSet):
swagger_schema = NoTitleAutoSchema
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
@list_route(methods=['get'])
def today(self, request):
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
articles = self.get_queryset().filter(date_created__range=(today_min, today_max)).all()
serializer = self.serializer_class(articles, many=True)
return Response(serializer.data)
try:
from rest_framework.decorators import action
@swagger_auto_schema(method='get', operation_description="image GET description override")
@swagger_auto_schema(method='post', request_body=serializers.ImageUploadSerializer)
@detail_route(methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, slug=None):
"""
image method docstring
"""
pass
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
@action(detail=False, methods=['get'])
def today(self, request):
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
articles = self.get_queryset().filter(date_created__range=(today_min, today_max)).all()
serializer = self.serializer_class(articles, many=True)
return Response(serializer.data)
@swagger_auto_schema(method='get', operation_description="image GET description override")
@swagger_auto_schema(method='post', request_body=serializers.ImageUploadSerializer)
@action(detail=True, methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, slug=None):
"""
image method docstring
"""
pass
except ImportError:
action = None
# noinspection PyDeprecation
@swagger_auto_schema(auto_schema=NoPagingAutoSchema, filter_inspectors=[DjangoFilterDescriptionInspector])
@list_route(methods=['get'])
def today(self, request):
today_min = datetime.datetime.combine(datetime.date.today(), datetime.time.min)
today_max = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
articles = self.get_queryset().filter(date_created__range=(today_min, today_max)).all()
serializer = self.serializer_class(articles, many=True)
return Response(serializer.data)
# noinspection PyDeprecation
@swagger_auto_schema(method='get', operation_description="image GET description override")
@swagger_auto_schema(method='post', request_body=serializers.ImageUploadSerializer)
@detail_route(methods=['get', 'post'], parser_classes=(MultiPartParser,))
def image(self, request, slug=None):
"""
image method docstring
"""
pass
def update(self, request, *args, **kwargs):
"""update method docstring"""
+2 -4
View File
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.10 on 2018-03-18 16:22
from __future__ import unicode_literals
# Generated by Django 2.0.1 on 2018-03-18 18:32
from django.db import migrations, models
import django.db.models.deletion
@@ -26,7 +24,7 @@ class Migration(migrations.Migration):
name='Person',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('Identity', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='person', to='people.Identity')),
('identity', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='person', to='people.Identity')),
],
),
]
@@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.10 on 2018-03-18 17:04
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('people', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='person',
name='Identity',
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='person', to='people.Identity'),
),
]
+1 -2
View File
@@ -7,5 +7,4 @@ class Identity(models.Model):
class Person(models.Model):
Identity = models.OneToOneField(Identity, related_name='person',
on_delete=models.PROTECT)
identity = models.OneToOneField(Identity, related_name='person', on_delete=models.PROTECT)
+1 -1
View File
@@ -10,7 +10,7 @@ class IdentitySerializer(serializers.ModelSerializer):
class PersonSerializer(serializers.ModelSerializer):
identity = IdentitySerializer(read_only=True)
identity = IdentitySerializer()
class Meta:
model = Person
+1 -1
View File
@@ -1,4 +1,4 @@
# Generated by Django 2.0 on 2017-12-23 09:07
# Generated by Django 2.0.1 on 2018-03-18 18:32
from django.conf import settings
from django.db import migrations, models
+1 -3
View File
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-21 23:26
from __future__ import unicode_literals
# Generated by Django 2.0.1 on 2018-03-18 18:32
from django.db import migrations, models
import django.db.models.deletion
+6
View File
@@ -1,3 +1,4 @@
from django.conf.urls import url
from rest_framework import routers
from todo import views
@@ -8,3 +9,8 @@ router.register(r'another', views.TodoAnotherViewSet)
router.register(r'yetanother', views.TodoYetAnotherViewSet)
urlpatterns = router.urls
urlpatterns += [
url(r'^(?P<todo_id>\d+)/yetanother/(?P<yetanother_id>\d+)/$',
views.NestedTodoView.as_view(),),
]
+5
View File
@@ -1,4 +1,5 @@
from rest_framework import viewsets
from rest_framework.generics import RetrieveAPIView
from .models import Todo, TodoAnother, TodoYetAnother
from .serializer import TodoAnotherSerializer, TodoSerializer, TodoYetAnotherSerializer
@@ -20,3 +21,7 @@ class TodoAnotherViewSet(viewsets.ReadOnlyModelViewSet):
class TodoYetAnotherViewSet(viewsets.ReadOnlyModelViewSet):
queryset = TodoYetAnother.objects.all()
serializer_class = TodoYetAnotherSerializer
class NestedTodoView(RetrieveAPIView):
serializer_class = TodoYetAnotherSerializer
+22 -5
View File
@@ -546,6 +546,27 @@ paths:
description: A unique integer value identifying this todo.
required: true
type: integer
/todo/{todo_id}/yetanother/{yetanother_id}/:
get:
operationId: todo_yetanother_read
description: ''
parameters: []
responses:
'200':
description: ''
schema:
$ref: '#/definitions/TodoYetAnother'
tags:
- todo
parameters:
- name: todo_id
in: path
required: true
type: string
- name: yetanother_id
in: path
required: true
type: string
/users/:
get:
operationId: users_list
@@ -732,10 +753,9 @@ definitions:
title: LastName
type: string
maxLength: 30
readOnly: true
Person:
required:
- Identity
- identity
type: object
properties:
id:
@@ -744,9 +764,6 @@ definitions:
readOnly: true
identity:
$ref: '#/definitions/Identity'
Identity:
title: Identity
type: integer
Project:
required:
- projectName
+4 -2
View File
@@ -1,13 +1,14 @@
[tox]
envlist =
py27-django111-drf37,
py{34,35,36}-django{111,20}-drf37,
py{34,35,36}-django{111,20}-drf{37,38},
py36-django20-drfmaster,
lint, docs
[travis:env]
DRF =
3.7: drf37
3.8: drf38
master: drfmaster
[testenv]
@@ -16,6 +17,7 @@ deps =
django20: Django>=2.0,<2.1
drf37: djangorestframework>=3.7.7,<3.8
drf38: djangorestframework>=3.8.0,<3.9
# test with the latest build of django-rest-framework to get early warning of compatibility issues
drfmaster: https://github.com/encode/django-rest-framework/archive/master.tar.gz
@@ -66,4 +68,4 @@ known_third_party =
coreapi,coreschema,datadiff,dj_database_url,django,django_filters,djangorestframework_camel_case,flex,gunicorn,
inflection,pygments,pytest,rest_framework,ruamel,setuptools_scm,swagger_spec_validator,uritemplate,user_agents,
whitenoise
known_first_party = drf_yasg,testproj,articles,snippets,users,urlconfs
known_first_party = drf_yasg,testproj,articles,people,snippets,todo,users,urlconfs
+1 -1
View File
@@ -2,7 +2,7 @@
set -ev
npm update
cp node_modules/redoc/dist/redoc.min.js src/drf_yasg/static/drf-yasg/redoc/
cp node_modules/redoc/bundles/redoc.standalone.js src/drf_yasg/static/drf-yasg/redoc/redoc.min.js
cp -r node_modules/swagger-ui-dist src/drf_yasg/static/drf-yasg/
pushd src/drf_yasg/static/drf-yasg/swagger-ui-dist/ >/dev/null
rm -f package.json .npmignore README.md