mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-28 17:09:59 +03:00
integer primary key, doc, cleanup, lint, test
This commit is contained in:
parent
1535ee2a3c
commit
d8c6821563
|
@ -14,16 +14,18 @@ from django.db import models
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
|
|
||||||
from rest_framework import exceptions, renderers, serializers, permissions
|
from rest_framework import exceptions, permissions, renderers, serializers
|
||||||
from rest_framework.compat import uritemplate
|
from rest_framework.compat import uritemplate
|
||||||
from rest_framework.fields import _UnvalidatedField, empty
|
from rest_framework.fields import _UnvalidatedField, empty
|
||||||
|
from rest_framework.schemas.openapi_utils import (
|
||||||
|
TYPE_MAPPING, PolymorphicResponse
|
||||||
|
)
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.schemas.openapi_utils import TYPE_MAPPING, PolymorphicResponse
|
|
||||||
from .generators import BaseSchemaGenerator
|
from .generators import BaseSchemaGenerator
|
||||||
from .inspectors import ViewInspector
|
from .inspectors import ViewInspector
|
||||||
from .utils import get_pk_description, is_list_view
|
from .utils import get_pk_description, is_list_view
|
||||||
|
|
||||||
|
|
||||||
AUTHENTICATION_SCHEMES = {
|
AUTHENTICATION_SCHEMES = {
|
||||||
cls.authentication_class: cls
|
cls.authentication_class: cls
|
||||||
for cls in [import_string(cls) for cls in api_settings.SCHEMA_AUTHENTICATION_CLASSES]
|
for cls in [import_string(cls) for cls in api_settings.SCHEMA_AUTHENTICATION_CLASSES]
|
||||||
|
@ -180,7 +182,7 @@ class AutoSchema(ViewInspector):
|
||||||
action_or_method = getattr(self.view, getattr(self.view, 'action', method.lower()), None)
|
action_or_method = getattr(self.view, getattr(self.view, 'action', method.lower()), None)
|
||||||
view_doc = inspect.getdoc(self.view) or ''
|
view_doc = inspect.getdoc(self.view) or ''
|
||||||
action_doc = inspect.getdoc(action_or_method) or ''
|
action_doc = inspect.getdoc(action_or_method) or ''
|
||||||
return view_doc + '\n\n' + action_doc if action_doc else view_doc
|
return action_doc or view_doc
|
||||||
|
|
||||||
def get_auth(self, path, method):
|
def get_auth(self, path, method):
|
||||||
""" override this for custom behaviour """
|
""" override this for custom behaviour """
|
||||||
|
@ -262,8 +264,10 @@ class AutoSchema(ViewInspector):
|
||||||
elif model_field is not None and model_field.primary_key:
|
elif model_field is not None and model_field.primary_key:
|
||||||
description = get_pk_description(model, model_field)
|
description = get_pk_description(model, model_field)
|
||||||
|
|
||||||
# TODO cover more cases
|
# TODO are there more relevant PK base classes?
|
||||||
if isinstance(model_field, models.UUIDField):
|
if isinstance(model_field, models.IntegerField):
|
||||||
|
schema = TYPE_MAPPING[int]
|
||||||
|
elif isinstance(model_field, models.UUIDField):
|
||||||
schema = TYPE_MAPPING[UUID]
|
schema = TYPE_MAPPING[UUID]
|
||||||
|
|
||||||
parameter = {
|
parameter = {
|
||||||
|
@ -498,7 +502,7 @@ class AutoSchema(ViewInspector):
|
||||||
result = {
|
result = {
|
||||||
'properties': properties
|
'properties': properties
|
||||||
}
|
}
|
||||||
if required and method != 'PATCH' and not nested:
|
if required and method != 'PATCH':
|
||||||
result['required'] = required
|
result['required'] = required
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -648,7 +652,6 @@ class AutoSchema(ViewInspector):
|
||||||
}
|
}
|
||||||
return {'200': self._get_response_for_code(path, method, schema)}
|
return {'200': self._get_response_for_code(path, method, schema)}
|
||||||
|
|
||||||
|
|
||||||
def _get_response_for_code(self, path, method, serializer_instance):
|
def _get_response_for_code(self, path, method, serializer_instance):
|
||||||
if not serializer_instance:
|
if not serializer_instance:
|
||||||
return {'description': 'No response body'}
|
return {'description': 'No response body'}
|
||||||
|
@ -702,7 +705,7 @@ class AutoSchema(ViewInspector):
|
||||||
|
|
||||||
if name.endswith('Serializer'):
|
if name.endswith('Serializer'):
|
||||||
name = name[:-10]
|
name = name[:-10]
|
||||||
if method == 'PATCH' and not nested:
|
if method == 'PATCH' and not serializer.read_only: # TODO maybe even use serializer.partial
|
||||||
name = 'Patched' + name
|
name = 'Patched' + name
|
||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import inspect
|
import inspect
|
||||||
import warnings
|
import warnings
|
||||||
|
from datetime import date, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from datetime import datetime, date
|
|
||||||
|
|
||||||
from rest_framework import authentication
|
from rest_framework import authentication
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
@ -103,6 +103,7 @@ def extend_schema(
|
||||||
TODO some heavy explaining
|
TODO some heavy explaining
|
||||||
|
|
||||||
:param operation:
|
:param operation:
|
||||||
|
:param operation_id:
|
||||||
:param extra_parameters:
|
:param extra_parameters:
|
||||||
:param responses:
|
:param responses:
|
||||||
:param request:
|
:param request:
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
from django.db import models
|
||||||
from django.test import RequestFactory, TestCase, override_settings
|
from django.test import RequestFactory, TestCase, override_settings
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import filters, generics, pagination, routers, serializers
|
from rest_framework import (
|
||||||
|
filters, generics, pagination, routers, serializers, viewsets
|
||||||
|
)
|
||||||
from rest_framework.compat import uritemplate
|
from rest_framework.compat import uritemplate
|
||||||
from rest_framework.parsers import JSONParser, MultiPartParser
|
from rest_framework.parsers import JSONParser, MultiPartParser
|
||||||
from rest_framework.renderers import JSONRenderer
|
from rest_framework.renderers import JSONRenderer
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.schemas.openapi import AutoSchema, SchemaGenerator, ComponentRegistry
|
from rest_framework.schemas.openapi import (
|
||||||
|
AutoSchema, ComponentRegistry, SchemaGenerator
|
||||||
|
)
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
|
@ -126,7 +131,7 @@ class TestOperationIntrospection(TestCase):
|
||||||
operation = inspector.get_operation(path, method)
|
operation = inspector.get_operation(path, method)
|
||||||
assert operation == {
|
assert operation == {
|
||||||
'operationId': 'example_retrieve',
|
'operationId': 'example_retrieve',
|
||||||
'description': '\n\nA description of my GET operation.',
|
'description': 'A description of my GET operation.',
|
||||||
'parameters': [
|
'parameters': [
|
||||||
{
|
{
|
||||||
'name': 'id',
|
'name': 'id',
|
||||||
|
@ -294,8 +299,7 @@ class TestOperationIntrospection(TestCase):
|
||||||
inspector = AutoSchema()
|
inspector = AutoSchema()
|
||||||
inspector.view = view
|
inspector.view = view
|
||||||
inspector.init(registry)
|
inspector.init(registry)
|
||||||
|
inspector.get_operation(path, method)
|
||||||
operation = inspector.get_operation(path, method)
|
|
||||||
example_schema = registry.schemas['Example']
|
example_schema = registry.schemas['Example']
|
||||||
nested_schema = registry.schemas['Nested']
|
nested_schema = registry.schemas['Nested']
|
||||||
|
|
||||||
|
@ -681,6 +685,36 @@ class TestOperationIntrospection(TestCase):
|
||||||
assert properties['ip']['type'] == 'string'
|
assert properties['ip']['type'] == 'string'
|
||||||
assert 'format' not in properties['ip']
|
assert 'format' not in properties['ip']
|
||||||
|
|
||||||
|
def test_modelviewset(self):
|
||||||
|
class ExampleModel(models.Model):
|
||||||
|
text = models.TextField()
|
||||||
|
|
||||||
|
class ExampleSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ExampleModel
|
||||||
|
fields = ['id', 'text']
|
||||||
|
|
||||||
|
class ExampleViewSet(viewsets.ModelViewSet):
|
||||||
|
serializer_class = ExampleSerializer
|
||||||
|
queryset = ExampleModel.objects.none()
|
||||||
|
|
||||||
|
from django.urls import path, include
|
||||||
|
|
||||||
|
router = routers.DefaultRouter()
|
||||||
|
router.register(r'example', ExampleViewSet)
|
||||||
|
|
||||||
|
generator = SchemaGenerator(patterns=[
|
||||||
|
path(r'api/', include(router.urls))
|
||||||
|
])
|
||||||
|
generator._initialise_endpoints()
|
||||||
|
|
||||||
|
schema = generator.get_schema(request=None, public=True)
|
||||||
|
|
||||||
|
assert list(schema['paths']['/api/example/'].keys()) == ['get', 'post']
|
||||||
|
assert list(schema['paths']['/api/example/{id}/'].keys()) == ['get', 'put', 'patch', 'delete']
|
||||||
|
assert list(schema['components']['schemas'].keys()) == ['Example', 'PatchedExample']
|
||||||
|
# TODO do more checks
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(uritemplate is None, reason='uritemplate not installed.')
|
@pytest.mark.skipif(uritemplate is None, reason='uritemplate not installed.')
|
||||||
@override_settings(REST_FRAMEWORK={'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema'})
|
@override_settings(REST_FRAMEWORK={'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema'})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user