def get_fields_params(self) -> []: if self.method != "GET": return [] response_serializers = self.get_response_serializers() if isinstance(response_serializers, DynamicFieldsMixin): return [ OpenApiParameter( name="fields", type=str, location=OpenApiParameter.QUERY, required=False, description=_( "Comma-separated fields, which should be displayed in the response. " "For example: 'url, uuid, record__geometry'."), ), OpenApiParameter( name=settings.UNAUTHORIZED_FIELDS_HEADER, type=str, location=OpenApiParameter.HEADER, response=True, description= _("List of fields that are not allowed to display if the field-based " "authorization is turned on. The value has the following format: " "`objectType1:fieldA,fieldB; objectType2:fieldC,fieldD`" ), ), ] return []
class QueryRegionGroupReservationView(views.APIView): @extend_schema( parameters=[ OpenApiParameter("min_time_id", OpenApiTypes.INT), OpenApiParameter("max_time_id", OpenApiTypes.INT), OpenApiParameter("region_group_id", OpenApiTypes.INT), ], responses=RegionReservationSerializer(many=True), ) def get(self, request): """ 查询某一区域组的预定情况,返回一个数组,代表在该区域组里的每一个区域在 [min_time_id, max_time_id] 每个时间段内的预定情况。 """ group = request.GET.get('region_group_id') min_time_id = request.GET.get('min_time_id') max_time_id = request.GET.get('max_time_id') reserved_time = Reservation.objects \ .filter(time__gte=min_time_id, time__lte=max_time_id, region__group=group) \ .values('region', 'time') \ .annotate(reserved=Count('*')) \ .annotate(region_id=F('region')) \ .annotate(time_id=F('time')) \ .values('region_id', 'time_id', 'reserved') serializer = RegionReservationSerializer(reserved_time, many=True) return Response(serializer.data)
class MenuList(ListCreateAPIView): """ Get list of non-empty menus with GET, or create a new one with POST. """ permission_classes = [IsAuthenticatedOrReadOnly] def get_serializer_class(self): if self.request.method == 'GET': return MenuListSerializer else: return MenuCreateSerializer def get_queryset(self): if self.request.method == 'GET': qs = Menu.objects.exclude(dishes__isnull=True) return filter_menu_queryset(qs, self.request.query_params) else: return Menu.objects.all() @extend_schema(parameters=[ OpenApiParameter( 'sort_by', description='Choose to sort list by name or dish count, descending', enum=['name', 'dish_count']), OpenApiParameter( 'updated_after', description= 'View only menus created after a date in YYYY-MM-DD format'), OpenApiParameter( 'added_after', description= 'View only menus updated after a date in YYYY-MM-DD format'), ]) def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)
class ListCreateMarketsView(MultipleFieldsSearch, ListCreateAPIView): queryset = Market.objects.all() serializer_class = MarketSerializer lookup_fields = ['district', 'region_5', 'name', 'address_city'] @extend_schema(description='Create a Market') def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) @extend_schema( description='List Markets with optional filters', parameters=[ OpenApiParameter(name='district', description='District', required=False, type=str, location='query'), OpenApiParameter(name='region_5', description='Region', required=False, type=str, location='query'), OpenApiParameter(name='name', description='Name', required=False, type=str, location='query'), OpenApiParameter(name='address_city', description='City', required=False, type=str, location='query'), ], ) def get(self, request, *args, **kwargs): if not bool(set(self.request.query_params).intersection(self.lookup_fields)): return JsonResponse({'message': "Should include at least one query param: [district,region_5,name,address_city]"}, status=400) return self.list(request, *args, **kwargs)
class ParametersViewSet(viewsets.ViewSet): """Parameter viewset.""" lookup_value_regex = r"\w+" serializer_class = None @extend_schema(responses=serializers.ApplicationSerializer(many=True)) @action(methods=["get"], detail=False) def applications(self, request): """Return the list of registered applications.""" applications = tools.registry.get_applications("global") return response.Response(applications) @extend_schema(responses=serializers.ParameterSerializer(many=True)) @action(methods=["get"], detail=False) def structure(self, request): """Return parameter schema.""" app = request.GET.get("app") data = tools.registry.get_structure("global", app) return response.Response(data) @extend_schema(parameters=[ OpenApiParameter(name='id', location=OpenApiParameter.PATH, description='A registered application name', type=str, required=True), ]) def retrieve(self, request, pk: str): """Return all parameters for given app.""" parameters = request.localconfig.parameters.get_values_dict(pk) serializer = tools.registry.get_serializer_class("global", pk)(parameters) return response.Response(serializer.data) @extend_schema(parameters=[ OpenApiParameter(name='id', location=OpenApiParameter.PATH, description='A registered application name', type=str, required=True), ]) def update(self, request, pk: str): """Save parameters for given app.""" serializer = tools.registry.get_serializer_class("global", pk)(data=request.data) serializer.is_valid(raise_exception=True) request.localconfig.parameters.set_values(serializer.validated_data, app=pk) request.localconfig.save(update_fields=["_parameters"]) return response.Response()
class SCIM_PARAMS: MEMBER_ID = OpenApiParameter( name="member_id", location="path", required=True, type=int, description="The id of the member you'd like to query.", ) TEAM_ID = OpenApiParameter( name="team_id", location="path", required=True, type=int, description="The id of the team you'd like to query / update.", )
class GLOBAL_PARAMS: ORG_SLUG = OpenApiParameter( name="organization_slug", description="The slug of the organization the resource belongs to.", required=True, type=str, location="path", ) PROJECT_SLUG = OpenApiParameter( name="project_slug", description="The slug of the project the resource belongs to.", required=True, type=str, location="path", )
def get_geo_headers(self) -> list: if not isinstance(self.view, GeoMixin): return [] request_headers = [] if self.method != "DELETE": request_headers.append( OpenApiParameter( name=HEADER_ACCEPT, type=str, location=OpenApiParameter.HEADER, required=False, description= _("The desired 'Coordinate Reference System' (CRS) of the response data. " "According to the GeoJSON spec, WGS84 is the default (EPSG: 4326 " "is the same as WGS84)."), enum=[DEFAULT_CRS], )) if self.method in ("POST", "PUT", "PATCH"): request_headers.append( OpenApiParameter( name=HEADER_CONTENT, type=str, location=OpenApiParameter.HEADER, required=True, description= _("The 'Coordinate Reference System' (CRS) of the request data. " "According to the GeoJSON spec, WGS84 is the default (EPSG: 4326 " "is the same as WGS84)."), enum=[DEFAULT_CRS], ), ) response_headers = [ OpenApiParameter( name=HEADER_CONTENT, type=str, location=OpenApiParameter.HEADER, description= _("The 'Coordinate Reference System' (CRS) of the request data. " "According to the GeoJSON spec, WGS84 is the default (EPSG: 4326 " "is the same as WGS84)."), enum=[DEFAULT_CRS], response=[200, 201], ) ] return request_headers + response_headers
class ExportTableView(APIView): permission_classes = (IsAuthenticated, ) @extend_schema( parameters=[ OpenApiParameter( name="table_id", location=OpenApiParameter.PATH, type=OpenApiTypes.INT, description= "The table id to create and start an export job for", ) ], tags=["Database table export"], operation_id="export_table", description= ("Creates and starts a new export job for a table given some exporter " "options. Returns an error if the requesting user does not have permissions" "to view the table."), request=CreateExportJobSerializer, responses={ 200: ExportJobSerializer, 400: get_error_schema([ "ERROR_USER_NOT_IN_GROUP", "ERROR_REQUEST_BODY_VALIDATION", "ERROR_TABLE_ONLY_EXPORT_UNSUPPORTED", "ERROR_VIEW_UNSUPPORTED_FOR_EXPORT_TYPE", "ERROR_VIEW_NOT_IN_TABLE", ]), 404: get_error_schema( ["ERROR_TABLE_DOES_NOT_EXIST", "ERROR_VIEW_DOES_NOT_EXIST"]), }, ) @transaction.atomic @map_exceptions({ UserNotInGroup: ERROR_USER_NOT_IN_GROUP, TableDoesNotExist: ERROR_TABLE_DOES_NOT_EXIST, ViewDoesNotExist: ERROR_VIEW_DOES_NOT_EXIST, TableOnlyExportUnsupported: ERROR_TABLE_ONLY_EXPORT_UNSUPPORTED, ViewNotInTable: ERROR_VIEW_NOT_IN_TABLE, }) def post(self, request, table_id): """ Starts a new export job for the provided table, view, export type and options. """ table = TableHandler().get_table(table_id) table.database.group.has_user(request.user, raise_error=True) option_data = _validate_options(request.data) view_id = option_data.pop("view_id", None) view = ViewHandler().get_view(view_id) if view_id else None job = ExportHandler.create_and_start_new_job(request.user, table, view, option_data) return Response(ExportJobSerializer(job).data)
class RegionRecommendationView(views.APIView): permission_classes = [permissions.IsAuthenticated] @extend_schema( parameters=[ OpenApiParameter("id", OpenApiTypes.INT, OpenApiParameter.PATH), ], responses=RegionGroupSerializer(many=True), ) def get(self, request): """ 根据用户的预定历史推荐区域 """ region_ids = Reservation.objects \ .filter(user=request.user) \ .values_list('region', flat=True) \ .distinct() group_ids = Region.objects \ .filter(id__in=region_ids) \ .values_list('group', flat=True) \ .distinct() region_groups = RegionGroup.objects \ .filter(id__in=group_ids) \ .annotate(capacity=Sum('regions__capacity')) serializer = RegionGroupDetailSerializer(region_groups, many=True) return Response(serializer.data)
class EventViewSet(ReadOnlyModelViewSet): """Event Read-Only Viewset""" queryset = Event.objects.all() serializer_class = EventSerializer ordering = ["-created"] search_fields = [ "event_uuid", "user", "action", "app", "context", "client_ip", ] filterset_class = EventsFilter @extend_schema( methods=["GET"], responses={200: EventTopPerUserSerializer(many=True)}, parameters=[ OpenApiParameter( "top_n", type=OpenApiTypes.INT, location=OpenApiParameter.QUERY, required=False, ) ], ) @action(detail=False, methods=["GET"], pagination_class=None) def top_per_user(self, request: Request): """Get the top_n events grouped by user count""" filtered_action = request.query_params.get("action", EventAction.LOGIN) top_n = int(request.query_params.get("top_n", "15")) return Response( get_objects_for_user( request.user, "authentik_events.view_event").filter( action=filtered_action).exclude( context__authorized_application=None).annotate( application=KeyTextTransform( "authorized_application", "context")).annotate( user_pk=KeyTextTransform("pk", "user")). values("application").annotate( counted_events=Count("application")).annotate( unique_users=Count("user_pk", distinct=True)).values( "unique_users", "application", "counted_events").order_by("-counted_events")[:top_n]) @extend_schema(responses={200: TypeCreateSerializer(many=True)}) @action(detail=False, pagination_class=None, filter_backends=[]) def actions(self, request: Request) -> Response: """Get all actions""" data = [] for value, name in EventAction.choices: data.append({ "name": name, "description": "", "component": value, "model_name": "" }) return Response(TypeCreateSerializer(data, many=True).data)
def test_exclude_discovered_parameter(no_warnings): @extend_schema_view(list=extend_schema(parameters=[ # keep 'offset', remove 'limit', and add 'random' OpenApiParameter('limit', exclude=True), OpenApiParameter('random', bool), ])) class XViewset(viewsets.ReadOnlyModelViewSet): queryset = SimpleModel.objects.all() serializer_class = SimpleSerializer pagination_class = pagination.LimitOffsetPagination schema = generate_schema('x', XViewset) parameters = schema['paths']['/x/']['get']['parameters'] assert len(parameters) == 2 assert parameters[0]['name'] == 'offset' assert parameters[1]['name'] == 'random'
def test_explode_style_parameter_with_custom_schema(no_warnings): @extend_schema( parameters=[ OpenApiParameter( name='bbox', type={ 'type': 'array', 'minItems': 4, 'maxItems': 6, 'items': { 'type': 'number' } }, location=OpenApiParameter.QUERY, required=False, style='form', explode=False, ) ], responses=OpenApiTypes.OBJECT, ) @api_view(['GET']) def view_func(request, format=None): pass # pragma: no cover schema = generate_schema('/x/', view_function=view_func) parameter = schema['paths']['/x/']['get']['parameters'][0] assert 'explode' in parameter assert 'style' in parameter assert parameter['schema']['type'] == 'array'
class NodeViewSet(ViewSet): serializer_class = NodeSerializer @extend_schema(parameters=[ OpenApiParameter('id', location=OpenApiParameter.PATH, description=PK_DESCRIPTION) ]) def retrieve(self, request, pk: str = None): assert pk is not None blockchain = BlockchainBase.get_instance() node_id = hexstr(pk.lower()) if node_id == PRIMARY_VALIDATOR_NODE_ID: node = blockchain.get_primary_validator() elif node_id == SELF_NODE_ID: node = blockchain.get_node_by_identifier( identifier=get_node_identifier()) else: node = blockchain.get_node_by_identifier(identifier=node_id) if node is None: raise NotFound(detail='Node not found') serializer = self.serializer_class(node) return Response(serializer.data)
class Fixed(self.target_class): @extend_schema(parameters=[ OpenApiParameter(name='breadcrumbs', type=OpenApiTypes.STR, location=OpenApiParameter.PATH) ]) def get(self, request, *args, **kwargs): pass
class ISSUE_ALERT_PARAMS: ISSUE_RULE_ID = OpenApiParameter( name="rule_id", location="path", required=True, type=int, description="The id of the rule you'd like to query", )
class DocsParams: KPIS = OpenApiParameter(name='kpis', type=OpenApiTypes.STR, description='get tiles for specific kpis') TABLE = OpenApiParameter(name='table', type=OpenApiTypes.STR, required=True, description="get specific graph by it's Name") TABLE_NAME = OpenApiParameter( 'table_name', type=OpenApiTypes.STR, description="get specific graph by it's Name") ID = OpenApiParameter( name='id', description='id or array of ids you want to query (branch or group)') START_DATE = OpenApiParameter(name='start_date', type=OpenApiTypes.DATE, description='format: YYYY-MM-DD') END_DATE = OpenApiParameter(name='end_date', type=OpenApiTypes.DATE, description='format: YYYY-MM-DD') LEVEL = OpenApiParameter(name='level', type=OpenApiTypes.STR, required=True, enum=LEVELS_ENUM, description='level (farm/branch/group)') FARM_ID = OpenApiParameter(name='farm_id', type=OpenApiTypes.STR, required=True, description='specify farm/s') META_FARM_ID = OpenApiParameter( name='farm_id', type=OpenApiTypes.STR, required=True, description="get the farm's branches and groups IDs lists") KPIS = OpenApiParameter(name=KPIS, type=OpenApiTypes.STR, description='get tiles for specific kpis')
class XApiView(APIView): authentication_classes = [] @extend_schema( parameters=[OpenApiParameter('id', OpenApiTypes.INT, OpenApiParameter.PATH)], responses={200: XSerializer(many=True)}, ) def get(self, request): pass # pragma: no cover
def test_exclude_parameter_from_customized_autoschema(no_warnings): class CustomSchema(AutoSchema): def get_override_parameters(self): return [OpenApiParameter('test')] @extend_schema_view(list=extend_schema(parameters=[ OpenApiParameter('test', exclude=True), # exclude from class override OpenApiParameter('never_existed', exclude=True), # provoke error OpenApiParameter('keep', bool), # for sanity check ])) class XViewset(viewsets.ReadOnlyModelViewSet): queryset = SimpleModel.objects.all() serializer_class = SimpleSerializer schema = CustomSchema() schema = generate_schema('x', XViewset) parameters = schema['paths']['/x/']['get']['parameters'] assert len(parameters) == 1 assert parameters[0]['name'] == 'keep'
class XViewset(viewsets.GenericViewSet): @extend_schema(request=XSerializer, responses=YSerializer) def create(self, request): pass # pragma: no cover @extend_schema( request=XSerializer, responses=YSerializer, parameters=[OpenApiParameter('id', int, OpenApiParameter.PATH)]) def partial_update(self, request): pass # pragma: no cover
def test_response_header_warnings(capsys): @extend_schema(request=OpenApiTypes.ANY, responses=OpenApiTypes.ANY, parameters=[OpenApiParameter(name='test', response=True)]) @api_view(['POST']) def view_func(request, format=None): pass # pragma: no cover generate_schema('x', view_function=view_func) stderr = capsys.readouterr().err assert 'incompatible location type ignored' in stderr
class ReportParamsView(generics.GenericAPIView): def get_slit(self): return get_slits_dict()[self.request.query_params["slit_name"]] def get_data_source(self): return get_data_sources_dict()[ self.request.query_params["data_source_name"]] def get_report(self): return Report(self.get_data_source(), self.get_slit()) def get_params(self): raise NotImplementedError @extend_schema(parameters=[ OpenApiParameter("slit_name"), OpenApiParameter("data_source_name") ]) def get(self, request, *args, **kwargs): return Response(self.get_params())
class XViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): @extend_schema(responses=enveloper(XSerializer, True)) def list(self, request, *args, **kwargs): return super().list(request, *args, **kwargs) # pragma: no cover @extend_schema( responses=enveloper(XSerializer, False), parameters=[OpenApiParameter('id', int, OpenApiParameter.PATH)], ) def retrieve(self, request, *args, **kwargs): return super().retrieve(request, *args, **kwargs) # pragma: no cover
class TailoredSkillsViewSet(viewsets.GenericViewSet): serializer_class = TailoredSkillsSerializer pagination_class = None def get_queryset(self, query): # SearchVector is currently disabled as it does not work properly on AWS RDS due to lack of # pg_catalog.english support from the migrations file. Retaled discussions: # https://stackoverflow.com/q/40032685/10748367 # https://forums.aws.amazon.com/thread.jspa?threadID=143920 # return Vacancy.objects.filter(search_vector=query) return Vacancy.objects.filter(title__search=query) @extend_schema( parameters=[ OpenApiParameter( name="limit", type=int, required=False, description="A number of most wanted skills to display.", ), OpenApiParameter( name="q", required=True, description="A job title to be processed.", ), ], description= "Specify a job title and get the ranked skills that companies look for.", ) def list(self, request): query, limit, user_agent, ip_address = parse_request(request) save_query_with_metadata.delay(query, user_agent, ip_address) queryset = self.get_queryset(query) tailored_skills = sort_skills(queryset)[:limit] data = OrderedDict({ "vacancy_name": query, "number_of_vacancies": len(queryset), "rated_skills": tailored_skills, }) return Response(data)
class ExplicitPersonViewSet(viewsets.GenericViewSet): @extend_schema(request=explicit_poly_proxy, responses=explicit_poly_proxy) def create(self, request, *args, **kwargs): return Response({}) # pragma: no cover @extend_schema( request=explicit_poly_proxy, responses=explicit_poly_proxy, parameters=[OpenApiParameter('id', int, OpenApiParameter.PATH)], ) def partial_update(self, request, *args, **kwargs): return Response({}) # pragma: no cover
def id_or_type_parameter(name="id_or_type"): return OpenApiParameter( name, OpenApiTypes.STR, OpenApiParameter.PATH, required=True, description="A UUID or type string identifying the form.", examples=[ OpenApiExample( "UUID", "3fa85f64-5717-4562-b3fc-2c963f66afa6", ), OpenApiExample("Hacker Application Type", "hacker_application"), ])
def get_content_type_headers(self) -> list: if self.method not in ["POST", "PUT", "PATCH"]: return [] return [ OpenApiParameter( name="Content-Type", type=str, location=OpenApiParameter.HEADER, required=True, enum=["application/json"], description=_("Content type of the request body."), ) ]
class AccountStateViewSet(ViewSet): serializer_class = AccountStateSerializer # TODO(dmu) LOW: Are there better ways to generate correct documentation? @extend_schema(parameters=[OpenApiParameter('id', str, OpenApiParameter.PATH, description='Account number')]) def retrieve(self, request, pk=None): # TODO(dmu) MEDIUM: There is a room for performance optimization use something like `?fields=` to # retrieval of unneeded fields using get_account_balance() and # get_account_balance_lock() directly. # Also see `drf-flex-fields` and `django-restql`. assert pk is not None blockchain = BlockchainBase.get_instance() serializer = self.serializer_class(blockchain.get_account_state(pk)) return Response(serializer.data)
class RegionGroupDetailView(views.APIView): @extend_schema( parameters=[ OpenApiParameter("id", OpenApiTypes.INT, OpenApiParameter.PATH), ], responses=RegionGroupDetailSerializer(), ) def get(self, request, id): """ 查询区域组下面的所有区域 """ region_group = RegionGroup.objects.annotate( capacity=Sum('regions__capacity')).get(id=id) serializer = RegionGroupDetailSerializer(region_group) return Response(serializer.data)
class OAuthSourceViewSet(UsedByMixin, ModelViewSet): """Source Viewset""" queryset = OAuthSource.objects.all() serializer_class = OAuthSourceSerializer lookup_field = "slug" filterset_fields = [ "name", "slug", "enabled", "authentication_flow", "enrollment_flow", "policy_engine_mode", "user_matching_mode", "provider_type", "request_token_url", "authorization_url", "access_token_url", "profile_url", "consumer_key", "additional_scopes", ] ordering = ["name"] @extend_schema( responses={200: SourceTypeSerializer(many=True)}, parameters=[ OpenApiParameter( name="name", location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, ) ], ) @action(detail=False, pagination_class=None, filter_backends=[]) def source_types(self, request: Request) -> Response: """Get all creatable source types. If ?name is set, only returns the type for <name>. If <name> isn't found, returns the default type.""" data = [] if "name" in request.query_params: source_type = MANAGER.find_type(request.query_params.get("name")) if source_type.__class__ != SourceType: data.append(SourceTypeSerializer(source_type).data) else: for source_type in MANAGER.get(): data.append(SourceTypeSerializer(source_type).data) return Response(data)