Prepare for 1.1.0 (#30)
* refactor the view inspection process to be more modular and allow recursive customization * add operation_id argument to @swagger_auto_ * add inspections for min/max validators * add support for URLPathVersioning and NamespaceVersioning * integrate with djangorestframework-camel-case * fix bugs, improve tests and documentation
This commit is contained in:
+4
-3
@@ -1,14 +1,15 @@
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
from collections import OrderedDict
|
||||
|
||||
import pytest
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework.test import APIRequestFactory
|
||||
from rest_framework.views import APIView
|
||||
from ruamel import yaml
|
||||
|
||||
from drf_yasg import openapi, codecs
|
||||
from drf_yasg.codecs import yaml_sane_load
|
||||
from drf_yasg.generators import OpenAPISchemaGenerator
|
||||
|
||||
|
||||
@@ -47,7 +48,7 @@ def swagger(mock_schema_request):
|
||||
@pytest.fixture
|
||||
def swagger_dict(swagger):
|
||||
json_bytes = codec_json().encode(swagger)
|
||||
return json.loads(json_bytes.decode('utf-8'))
|
||||
return json.loads(json_bytes.decode('utf-8'), object_pairs_hook=OrderedDict)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -79,4 +80,4 @@ def redoc_settings(settings):
|
||||
@pytest.fixture
|
||||
def reference_schema():
|
||||
with open(os.path.join(os.path.dirname(__file__), 'reference.yaml')) as reference:
|
||||
return yaml.safe_load(reference)
|
||||
return yaml_sane_load(reference)
|
||||
|
||||
+49
-18
@@ -20,7 +20,7 @@ paths:
|
||||
parameters:
|
||||
- name: title
|
||||
in: query
|
||||
description: ''
|
||||
description: Filter the returned list by title
|
||||
required: false
|
||||
type: string
|
||||
- name: ordering
|
||||
@@ -89,7 +89,7 @@ paths:
|
||||
parameters:
|
||||
- name: title
|
||||
in: query
|
||||
description: ''
|
||||
description: Filter the returned list by title
|
||||
required: false
|
||||
type: string
|
||||
- name: ordering
|
||||
@@ -249,7 +249,7 @@ paths:
|
||||
parameters: []
|
||||
/snippets/:
|
||||
get:
|
||||
operationId: snippets_list
|
||||
operationId: snippetsList
|
||||
description: SnippetList classdoc
|
||||
parameters: []
|
||||
responses:
|
||||
@@ -264,7 +264,7 @@ paths:
|
||||
tags:
|
||||
- snippets
|
||||
post:
|
||||
operationId: snippets_create
|
||||
operationId: snippetsCreate
|
||||
description: post method docstring
|
||||
parameters:
|
||||
- name: data
|
||||
@@ -284,7 +284,7 @@ paths:
|
||||
parameters: []
|
||||
/snippets/{id}/:
|
||||
get:
|
||||
operationId: snippets_read
|
||||
operationId: snippetsRead
|
||||
description: SnippetDetail classdoc
|
||||
parameters: []
|
||||
responses:
|
||||
@@ -297,7 +297,7 @@ paths:
|
||||
tags:
|
||||
- snippets
|
||||
put:
|
||||
operationId: snippets_update
|
||||
operationId: snippetsUpdate
|
||||
description: put class docstring
|
||||
parameters:
|
||||
- name: data
|
||||
@@ -315,7 +315,7 @@ paths:
|
||||
tags:
|
||||
- snippets
|
||||
patch:
|
||||
operationId: snippets_partial_update
|
||||
operationId: snippetsPartialUpdate
|
||||
description: patch method docstring
|
||||
parameters:
|
||||
- name: data
|
||||
@@ -333,7 +333,7 @@ paths:
|
||||
tags:
|
||||
- snippets
|
||||
delete:
|
||||
operationId: snippets_delete
|
||||
operationId: snippetsDelete
|
||||
description: delete method docstring
|
||||
parameters: []
|
||||
responses:
|
||||
@@ -404,7 +404,7 @@ paths:
|
||||
tags:
|
||||
- users
|
||||
patch:
|
||||
operationId: users_partial_update
|
||||
operationId: users_dummy
|
||||
description: dummy operation
|
||||
parameters: []
|
||||
responses:
|
||||
@@ -466,6 +466,7 @@ definitions:
|
||||
title:
|
||||
description: title model help_text
|
||||
type: string
|
||||
maxLength: 255
|
||||
author:
|
||||
description: The ID of the user that created this article; if none is provided,
|
||||
defaults to the currently logged in user.
|
||||
@@ -474,11 +475,13 @@ definitions:
|
||||
body:
|
||||
description: body serializer help_text
|
||||
type: string
|
||||
maxLength: 5000
|
||||
slug:
|
||||
description: slug model help_text
|
||||
type: string
|
||||
format: slug
|
||||
pattern: ^[-a-zA-Z0-9_]+$
|
||||
maxLength: 50
|
||||
date_created:
|
||||
type: string
|
||||
format: date-time
|
||||
@@ -509,14 +512,16 @@ definitions:
|
||||
readOnly: true
|
||||
Project:
|
||||
required:
|
||||
- project_name
|
||||
- github_repo
|
||||
- projectName
|
||||
- githubRepo
|
||||
type: object
|
||||
properties:
|
||||
project_name:
|
||||
projectName:
|
||||
title: Project name
|
||||
description: Name of the project
|
||||
type: string
|
||||
github_repo:
|
||||
githubRepo:
|
||||
title: Github repo
|
||||
description: Github repository of the project
|
||||
type: string
|
||||
Snippet:
|
||||
@@ -526,29 +531,38 @@ definitions:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: Id
|
||||
description: id serializer help text
|
||||
type: integer
|
||||
readOnly: true
|
||||
owner:
|
||||
title: Owner
|
||||
description: The ID of the user that created this snippet; if none is provided,
|
||||
defaults to the currently logged in user.
|
||||
type: integer
|
||||
default: 1
|
||||
owner_as_string:
|
||||
ownerAsString:
|
||||
description: The ID of the user that created this snippet.
|
||||
type: string
|
||||
readOnly: true
|
||||
title: Owner as string
|
||||
title:
|
||||
title: Title
|
||||
type: string
|
||||
maxLength: 100
|
||||
code:
|
||||
title: Code
|
||||
type: string
|
||||
linenos:
|
||||
title: Linenos
|
||||
type: boolean
|
||||
language:
|
||||
title: Language
|
||||
description: Sample help text for language
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
title: Name
|
||||
description: The name of the programming language
|
||||
type: string
|
||||
enum:
|
||||
@@ -988,6 +1002,7 @@ definitions:
|
||||
- zephir
|
||||
default: python
|
||||
styles:
|
||||
title: Styles
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
@@ -1024,19 +1039,22 @@ definitions:
|
||||
default:
|
||||
- friendly
|
||||
lines:
|
||||
title: Lines
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
example_projects:
|
||||
exampleProjects:
|
||||
title: Example projects
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Project'
|
||||
readOnly: true
|
||||
difficulty_factor:
|
||||
difficultyFactor:
|
||||
title: Difficulty factor
|
||||
description: this is here just to test FloatField
|
||||
type: number
|
||||
default: 6.9
|
||||
readOnly: true
|
||||
default: 6.9
|
||||
UserSerializerrr:
|
||||
required:
|
||||
- username
|
||||
@@ -1045,42 +1063,55 @@ definitions:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
title: ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
username:
|
||||
title: Username
|
||||
description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_
|
||||
only.
|
||||
type: string
|
||||
pattern: ^[\w.@+-]+$
|
||||
maxLength: 150
|
||||
email:
|
||||
title: Email address
|
||||
type: string
|
||||
format: email
|
||||
maxLength: 254
|
||||
articles:
|
||||
title: Articles
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
uniqueItems: true
|
||||
snippets:
|
||||
title: Snippets
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
uniqueItems: true
|
||||
last_connected_ip:
|
||||
title: Last connected ip
|
||||
description: i'm out of ideas
|
||||
type: string
|
||||
format: ipv4
|
||||
readOnly: true
|
||||
last_connected_at:
|
||||
title: Last connected at
|
||||
description: really?
|
||||
type: string
|
||||
format: date
|
||||
readOnly: true
|
||||
article_slugs:
|
||||
title: Article slugs
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: slug
|
||||
pattern: ^[-a-zA-Z0-9_]+\Z
|
||||
readOnly: true
|
||||
uniqueItems: true
|
||||
readOnly: true
|
||||
uniqueItems: true
|
||||
securityDefinitions:
|
||||
basic:
|
||||
type: basic
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from drf_yasg import openapi
|
||||
|
||||
|
||||
def test_operation_docstrings(swagger_dict):
|
||||
users_list = swagger_dict['paths']['/users/']
|
||||
assert users_list['get']['description'] == "UserList cbv classdoc"
|
||||
assert users_list['post']['description'] == "apiview post description override"
|
||||
|
||||
users_detail = swagger_dict['paths']['/users/{id}/']
|
||||
assert users_detail['get']['description'] == "user_detail fbv docstring"
|
||||
assert users_detail['put']['description'] == "user_detail fbv docstring"
|
||||
|
||||
|
||||
def test_parameter_docstrings(swagger_dict):
|
||||
users_detail = swagger_dict['paths']['/users/{id}/']
|
||||
assert users_detail['get']['parameters'][0]['description'] == "test manual param"
|
||||
assert users_detail['put']['parameters'][0]['in'] == openapi.IN_BODY
|
||||
@@ -1,22 +0,0 @@
|
||||
def test_appropriate_status_codes(swagger_dict):
|
||||
snippets_list = swagger_dict['paths']['/snippets/']
|
||||
assert '200' in snippets_list['get']['responses']
|
||||
assert '201' in snippets_list['post']['responses']
|
||||
|
||||
snippets_detail = swagger_dict['paths']['/snippets/{id}/']
|
||||
assert '200' in snippets_detail['get']['responses']
|
||||
assert '200' in snippets_detail['put']['responses']
|
||||
assert '200' in snippets_detail['patch']['responses']
|
||||
assert '204' in snippets_detail['delete']['responses']
|
||||
|
||||
|
||||
def test_operation_docstrings(swagger_dict):
|
||||
snippets_list = swagger_dict['paths']['/snippets/']
|
||||
assert snippets_list['get']['description'] == "SnippetList classdoc"
|
||||
assert snippets_list['post']['description'] == "post method docstring"
|
||||
|
||||
snippets_detail = swagger_dict['paths']['/snippets/{id}/']
|
||||
assert snippets_detail['get']['description'] == "SnippetDetail classdoc"
|
||||
assert snippets_detail['put']['description'] == "put class docstring"
|
||||
assert snippets_detail['patch']['description'] == "patch method docstring"
|
||||
assert snippets_detail['delete']['description'] == "delete method docstring"
|
||||
@@ -1,29 +0,0 @@
|
||||
def test_appropriate_status_codes(swagger_dict):
|
||||
articles_list = swagger_dict['paths']['/articles/']
|
||||
assert '200' in articles_list['get']['responses']
|
||||
assert '201' in articles_list['post']['responses']
|
||||
|
||||
articles_detail = swagger_dict['paths']['/articles/{slug}/']
|
||||
assert '200' in articles_detail['get']['responses']
|
||||
assert '200' in articles_detail['put']['responses']
|
||||
assert '200' in articles_detail['patch']['responses']
|
||||
assert '204' in articles_detail['delete']['responses']
|
||||
|
||||
|
||||
def test_operation_docstrings(swagger_dict):
|
||||
articles_list = swagger_dict['paths']['/articles/']
|
||||
assert articles_list['get']['description'] == "description from swagger_auto_schema via method_decorator"
|
||||
assert articles_list['post']['description'] == "ArticleViewSet class docstring"
|
||||
|
||||
articles_detail = swagger_dict['paths']['/articles/{slug}/']
|
||||
assert articles_detail['get']['description'] == "retrieve class docstring"
|
||||
assert articles_detail['put']['description'] == "update method docstring"
|
||||
assert articles_detail['patch']['description'] == "partial_update description override"
|
||||
assert articles_detail['delete']['description'] == "destroy method docstring"
|
||||
|
||||
articles_today = swagger_dict['paths']['/articles/today/']
|
||||
assert articles_today['get']['description'] == "ArticleViewSet class docstring"
|
||||
|
||||
articles_image = swagger_dict['paths']['/articles/{slug}/image/']
|
||||
assert articles_image['get']['description'] == "image GET description override"
|
||||
assert articles_image['post']['description'] == "image method docstring"
|
||||
@@ -1,13 +1,46 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
from datadiff.tools import assert_equal
|
||||
|
||||
from drf_yasg.codecs import yaml_sane_dump
|
||||
from drf_yasg.inspectors import FieldInspector, SerializerInspector, PaginatorInspector, FilterInspector
|
||||
|
||||
|
||||
def test_reference_schema(swagger_dict, reference_schema):
|
||||
swagger_dict = dict(swagger_dict)
|
||||
reference_schema = dict(reference_schema)
|
||||
swagger_dict = OrderedDict(swagger_dict)
|
||||
reference_schema = OrderedDict(reference_schema)
|
||||
ignore = ['info', 'host', 'schemes', 'basePath', 'securityDefinitions']
|
||||
for attr in ignore:
|
||||
swagger_dict.pop(attr, None)
|
||||
reference_schema.pop(attr, None)
|
||||
|
||||
# formatted better than pytest diff
|
||||
assert_equal(swagger_dict, reference_schema)
|
||||
# print diff between YAML strings because it's prettier
|
||||
assert_equal(yaml_sane_dump(swagger_dict, binary=False), yaml_sane_dump(reference_schema, binary=False))
|
||||
|
||||
|
||||
class NoOpFieldInspector(FieldInspector):
|
||||
pass
|
||||
|
||||
|
||||
class NoOpSerializerInspector(SerializerInspector):
|
||||
pass
|
||||
|
||||
|
||||
class NoOpFilterInspector(FilterInspector):
|
||||
pass
|
||||
|
||||
|
||||
class NoOpPaginatorInspector(PaginatorInspector):
|
||||
pass
|
||||
|
||||
|
||||
def test_noop_inspectors(swagger_settings, swagger_dict, reference_schema):
|
||||
from drf_yasg import app_settings
|
||||
|
||||
def set_inspectors(inspectors, setting_name):
|
||||
swagger_settings[setting_name] = inspectors + app_settings.SWAGGER_DEFAULTS[setting_name]
|
||||
|
||||
set_inspectors([NoOpFieldInspector, NoOpSerializerInspector], 'DEFAULT_FIELD_INSPECTORS')
|
||||
set_inspectors([NoOpFilterInspector], 'DEFAULT_FILTER_INSPECTORS')
|
||||
set_inspectors([NoOpPaginatorInspector], 'DEFAULT_PAGINATOR_INSPECTORS')
|
||||
test_reference_schema(swagger_dict, reference_schema)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
|
||||
import pytest
|
||||
from ruamel import yaml
|
||||
|
||||
from drf_yasg import openapi, codecs
|
||||
from drf_yasg.codecs import yaml_sane_load
|
||||
from drf_yasg.generators import OpenAPISchemaGenerator
|
||||
|
||||
|
||||
@@ -35,12 +36,12 @@ def test_yaml_codec_roundtrip(codec_yaml, swagger, validate_schema):
|
||||
yaml_bytes = codec_yaml.encode(swagger)
|
||||
assert b'omap' not in yaml_bytes # ensure no ugly !!omap is outputted
|
||||
assert b'&id' not in yaml_bytes and b'*id' not in yaml_bytes # ensure no YAML references are generated
|
||||
validate_schema(yaml.safe_load(yaml_bytes.decode('utf-8')))
|
||||
validate_schema(yaml_sane_load(yaml_bytes.decode('utf-8')))
|
||||
|
||||
|
||||
def test_yaml_and_json_match(codec_yaml, codec_json, swagger):
|
||||
yaml_schema = yaml.safe_load(codec_yaml.encode(swagger).decode('utf-8'))
|
||||
json_schema = json.loads(codec_json.encode(swagger).decode('utf-8'))
|
||||
yaml_schema = yaml_sane_load(codec_yaml.encode(swagger).decode('utf-8'))
|
||||
json_schema = json.loads(codec_json.encode(swagger).decode('utf-8'), object_pairs_hook=OrderedDict)
|
||||
assert yaml_schema == json_schema
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
def test_paths_not_empty(swagger_dict):
|
||||
assert len(swagger_dict['paths']) > 0
|
||||
@@ -2,7 +2,8 @@ import json
|
||||
from collections import OrderedDict
|
||||
|
||||
import pytest
|
||||
from ruamel import yaml
|
||||
|
||||
from drf_yasg.codecs import yaml_sane_load
|
||||
|
||||
|
||||
def _validate_text_schema_view(client, validate_schema, path, loader):
|
||||
@@ -22,10 +23,10 @@ def test_swagger_json(client, validate_schema):
|
||||
|
||||
|
||||
def test_swagger_yaml(client, validate_schema):
|
||||
_validate_text_schema_view(client, validate_schema, "/swagger.yaml", yaml.safe_load)
|
||||
_validate_text_schema_view(client, validate_schema, "/swagger.yaml", yaml_sane_load)
|
||||
|
||||
|
||||
def test_exception_middleware(client, swagger_settings):
|
||||
def test_exception_middleware(client, swagger_settings, db):
|
||||
swagger_settings['SECURITY_DEFINITIONS'] = {
|
||||
'bad': {
|
||||
'bad_attribute': 'should not be accepted'
|
||||
@@ -70,5 +71,5 @@ def test_caching(client, validate_schema):
|
||||
@pytest.mark.urls('urlconfs.non_public_urls')
|
||||
def test_non_public(client):
|
||||
response = client.get('/private/swagger.yaml')
|
||||
swagger = yaml.safe_load(response.content.decode('utf-8'))
|
||||
swagger = yaml_sane_load(response.content.decode('utf-8'))
|
||||
assert len(swagger['paths']) == 0
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import pytest
|
||||
|
||||
from drf_yasg.codecs import yaml_sane_load
|
||||
|
||||
|
||||
def _get_versioned_schema(prefix, client, validate_schema):
|
||||
response = client.get(prefix + 'swagger.yaml')
|
||||
assert response.status_code == 200
|
||||
swagger = yaml_sane_load(response.content.decode('utf-8'))
|
||||
validate_schema(swagger)
|
||||
assert prefix + 'snippets/' in swagger['paths']
|
||||
return swagger
|
||||
|
||||
|
||||
def _check_v1(swagger, prefix):
|
||||
assert swagger['info']['version'] == '1.0'
|
||||
versioned_post = swagger['paths'][prefix + 'snippets/']['post']
|
||||
assert versioned_post['responses']['201']['schema']['$ref'] == '#/definitions/Snippet'
|
||||
assert 'v2field' not in swagger['definitions']['Snippet']['properties']
|
||||
|
||||
|
||||
def _check_v2(swagger, prefix):
|
||||
assert swagger['info']['version'] == '2.0'
|
||||
versioned_post = swagger['paths'][prefix + 'snippets/']['post']
|
||||
assert versioned_post['responses']['201']['schema']['$ref'] == '#/definitions/SnippetV2'
|
||||
assert 'v2field' in swagger['definitions']['SnippetV2']['properties']
|
||||
v2field = swagger['definitions']['SnippetV2']['properties']['v2field']
|
||||
assert v2field['description'] == 'version 2.0 field'
|
||||
|
||||
|
||||
@pytest.mark.urls('urlconfs.url_versioning')
|
||||
def test_url_v1(client, validate_schema):
|
||||
prefix = '/versioned/url/v1.0/'
|
||||
swagger = _get_versioned_schema(prefix, client, validate_schema)
|
||||
_check_v1(swagger, prefix)
|
||||
|
||||
|
||||
@pytest.mark.urls('urlconfs.url_versioning')
|
||||
def test_url_v2(client, validate_schema):
|
||||
prefix = '/versioned/url/v2.0/'
|
||||
swagger = _get_versioned_schema(prefix, client, validate_schema)
|
||||
_check_v2(swagger, prefix)
|
||||
|
||||
|
||||
@pytest.mark.urls('urlconfs.ns_versioning')
|
||||
def test_ns_v1(client, validate_schema):
|
||||
prefix = '/versioned/ns/v1.0/'
|
||||
swagger = _get_versioned_schema(prefix, client, validate_schema)
|
||||
_check_v1(swagger, prefix)
|
||||
|
||||
|
||||
@pytest.mark.urls('urlconfs.ns_versioning')
|
||||
def test_ns_v2(client, validate_schema):
|
||||
prefix = '/versioned/ns/v2.0/'
|
||||
swagger = _get_versioned_schema(prefix, client, validate_schema)
|
||||
_check_v2(swagger, prefix)
|
||||
@@ -0,0 +1,26 @@
|
||||
from django.conf.urls import url
|
||||
from rest_framework import generics, versioning
|
||||
|
||||
from snippets.models import Snippet
|
||||
from snippets.serializers import SnippetSerializer
|
||||
|
||||
|
||||
class SnippetList(generics.ListCreateAPIView):
|
||||
"""SnippetList classdoc"""
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
versioning_class = versioning.NamespaceVersioning
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""post method docstring"""
|
||||
return super(SnippetList, self).post(request, *args, **kwargs)
|
||||
|
||||
|
||||
app_name = 'test_ns_versioning'
|
||||
|
||||
urlpatterns = [
|
||||
url(r"^$", SnippetList.as_view())
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
from django.conf.urls import url
|
||||
from rest_framework import fields
|
||||
|
||||
from snippets.serializers import SnippetSerializer
|
||||
from .ns_version1 import SnippetList as SnippetListV1
|
||||
|
||||
|
||||
class SnippetSerializerV2(SnippetSerializer):
|
||||
v2field = fields.IntegerField(help_text="version 2.0 field")
|
||||
|
||||
class Meta:
|
||||
ref_name = 'SnippetV2'
|
||||
|
||||
|
||||
class SnippetListV2(SnippetListV1):
|
||||
serializer_class = SnippetSerializerV2
|
||||
|
||||
|
||||
app_name = 'test_ns_versioning'
|
||||
|
||||
urlpatterns = [
|
||||
url(r"^$", SnippetListV2.as_view())
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
from django.conf.urls import url, include
|
||||
from rest_framework import versioning
|
||||
|
||||
from testproj.urls import SchemaView
|
||||
from . import ns_version1, ns_version2
|
||||
|
||||
VERSION_PREFIX_NS = r"^versioned/ns/"
|
||||
|
||||
|
||||
class VersionedSchemaView(SchemaView):
|
||||
versioning_class = versioning.NamespaceVersioning
|
||||
|
||||
|
||||
schema_patterns = [
|
||||
url(r'swagger(?P<format>.json|.yaml)$', VersionedSchemaView.without_ui(), name='ns-schema')
|
||||
]
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(VERSION_PREFIX_NS + r"v1.0/snippets/", include(ns_version1, namespace='1.0')),
|
||||
url(VERSION_PREFIX_NS + r"v2.0/snippets/", include(ns_version2, namespace='2.0')),
|
||||
url(VERSION_PREFIX_NS + r'v1.0/', include((schema_patterns, '1.0'))),
|
||||
url(VERSION_PREFIX_NS + r'v2.0/', include((schema_patterns, '2.0'))),
|
||||
]
|
||||
@@ -0,0 +1,48 @@
|
||||
from django.conf.urls import url
|
||||
from rest_framework import generics, versioning, fields
|
||||
|
||||
from snippets.models import Snippet
|
||||
from snippets.serializers import SnippetSerializer
|
||||
from testproj.urls import SchemaView
|
||||
|
||||
|
||||
class SnippetSerializerV2(SnippetSerializer):
|
||||
v2field = fields.IntegerField(help_text="version 2.0 field")
|
||||
|
||||
class Meta:
|
||||
ref_name = 'SnippetV2'
|
||||
|
||||
|
||||
class SnippetList(generics.ListCreateAPIView):
|
||||
"""SnippetList classdoc"""
|
||||
queryset = Snippet.objects.all()
|
||||
serializer_class = SnippetSerializer
|
||||
versioning_class = versioning.URLPathVersioning
|
||||
|
||||
def get_serializer_class(self):
|
||||
context = self.get_serializer_context()
|
||||
request = context['request']
|
||||
if int(float(request.version)) >= 2:
|
||||
return SnippetSerializerV2
|
||||
else:
|
||||
return SnippetSerializer
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""post method docstring"""
|
||||
return super(SnippetList, self).post(request, *args, **kwargs)
|
||||
|
||||
|
||||
VERSION_PREFIX_URL = r"^versioned/url/v(?P<version>1.0|2.0)/"
|
||||
|
||||
|
||||
class VersionedSchemaView(SchemaView):
|
||||
versioning_class = versioning.URLPathVersioning
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(VERSION_PREFIX_URL + r"snippets/$", SnippetList.as_view()),
|
||||
url(VERSION_PREFIX_URL + r'swagger(?P<format>.json|.yaml)$', VersionedSchemaView.without_ui(), name='vschema-json'),
|
||||
]
|
||||
Reference in New Issue
Block a user