diff --git a/src/drf_yasg/inspectors/view.py b/src/drf_yasg/inspectors/view.py index 8ad8cc8..52b9319 100644 --- a/src/drf_yasg/inspectors/view.py +++ b/src/drf_yasg/inspectors/view.py @@ -8,8 +8,8 @@ from rest_framework.status import is_success from .. import openapi from ..errors import SwaggerGenerationError from ..utils import ( - force_real_str, force_serializer_instance, get_consumes, get_produces, guess_response_status, is_list_view, no_body, - param_list_to_odict + force_real_str, force_serializer_instance, get_consumes, get_produces, guess_response_status, is_list_view, + merge_params, no_body, param_list_to_odict ) from .base import ViewInspector @@ -162,21 +162,19 @@ class SwaggerAutoSchema(ViewInspector): :return: modified parameters :rtype: list[openapi.Parameter] """ - parameters = param_list_to_odict(parameters) manual_parameters = self.overrides.get('manual_parameters', None) or [] if any(param.in_ == openapi.IN_BODY for param in manual_parameters): # pragma: no cover raise SwaggerGenerationError("specify the body parameter as a Schema or Serializer in request_body") if any(param.in_ == openapi.IN_FORM for param in manual_parameters): # pragma: no cover - if any(param.in_ == openapi.IN_BODY for param in parameters.values()): + if any(param.in_ == openapi.IN_BODY for param in parameters): raise SwaggerGenerationError("cannot add form parameters when the request has a request body; " "did you forget to set an appropriate parser class on the view?") if self.method not in self.body_methods: raise SwaggerGenerationError("form parameters can only be applied to (" + ','.join(self.body_methods) + ") HTTP methods") - parameters.update(param_list_to_odict(manual_parameters)) - return list(parameters.values()) + return merge_params(parameters, manual_parameters) def get_responses(self): """Get the possible responses for this view as a swagger :class:`.Responses` object. diff --git a/src/drf_yasg/openapi.py b/src/drf_yasg/openapi.py index 8cb50eb..a88da60 100644 --- a/src/drf_yasg/openapi.py +++ b/src/drf_yasg/openapi.py @@ -291,6 +291,8 @@ class Paths(SwaggerDict): class PathItem(SwaggerDict): + OPERATION_NAMES = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch'] + def __init__(self, get=None, put=None, post=None, delete=None, options=None, head=None, patch=None, parameters=None, **extra): """Information about a single path @@ -315,6 +317,15 @@ class PathItem(SwaggerDict): self.parameters = filter_none(parameters) self._insert_extras__() + @property + def operations(self): + """A list of all standard Operations on this PathItem object. See :attr:`.OPERATION_NAMES`. + + :return: list of (method name, Operation) tuples + :rtype: list[tuple[str,Operation]] + """ + return [(k, v) for k, v in self.items() if k in PathItem.OPERATION_NAMES and v] + class Operation(SwaggerDict): def __init__(self, operation_id, responses, parameters=None, consumes=None, produces=None, summary=None, diff --git a/src/drf_yasg/utils.py b/src/drf_yasg/utils.py index 472c56d..b14fce8 100644 --- a/src/drf_yasg/utils.py +++ b/src/drf_yasg/utils.py @@ -254,6 +254,22 @@ def param_list_to_odict(parameters): return result +def merge_params(parameters, overrides): + """Merge `overrides` into `parameters`. This is the same as appending `overrides` to `parameters`, but any element + of `parameters` whose ``(name, in_)`` tuple collides with an element in `overrides` is replaced by it. + + Raises an ``AssertionError`` if either list contains duplicate parameters. + + :param list[.Parameter] parameters: initial parameters + :param list[.Parameter] overrides: overriding parameters + :return: merged list + :rtype: list[.Parameter] + """ + parameters = param_list_to_odict(parameters) + parameters.update(param_list_to_odict(overrides)) + return list(parameters.values()) + + def filter_none(obj): """Remove ``None`` values from tuples, lists or dictionaries. Return other objects as-is.