コード例 #1
0
def test_get_example_row_serializer_class():
    request_serializer = get_example_row_serializer_class()
    response_serializer = get_example_row_serializer_class(add_id=True)

    assert len(request_serializer._declared_fields) == \
           len(field_type_registry.registry.values())
    assert len(response_serializer._declared_fields) == \
           len(request_serializer._declared_fields) + 1
    assert len(response_serializer._declared_fields) == \
           len(field_type_registry.registry.values()) + 1

    assert isinstance(response_serializer._declared_fields['id'],
                      serializers.IntegerField)

    # This assert depends on TextField to be added first in the
    # `baserow.contrib.database.config` module.
    assert isinstance(response_serializer._declared_fields['field_1'],
                      serializers.CharField)
コード例 #2
0
ファイル: views.py プロジェクト: zarybnicky/baserow
class GridViewView(APIView):
    permission_classes = (IsAuthenticated, )

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name='view_id',
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.INT,
                description=
                'Returns only rows that belong to the related view\'s '
                'table.'),
            OpenApiParameter(
                name='count',
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.NONE,
                description='If provided only the count will be returned.'),
            OpenApiParameter(
                name='include',
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description=
                ('Can contain `field_options` which will add an object with the '
                 'same name to the response if included. That object contains '
                 'user defined view settings for each field. For example the '
                 'field\'s width is included in here.')),
            OpenApiParameter(
                name='limit',
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description='Defines how many rows should be returned.'),
            OpenApiParameter(
                name='offset',
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description='Can only be used in combination with the `limit` '
                'parameter and defines from which offset the rows should '
                'be returned.'),
            OpenApiParameter(
                name='page',
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description=
                'Defines which page of rows should be returned. Either '
                'the `page` or `limit` can be provided, not both.'),
            OpenApiParameter(
                name='size',
                location=
                OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description=
                'Can only be used in combination with the `page` parameter '
                'and defines how many rows should be returned.')
        ],
        tags=['Database table grid view'],
        operation_id='list_database_table_grid_view_rows',
        description
        =
        ('Lists the requested rows of the view\'s table related to the provided '
         '`view_id` if the authorized user has access to the database\'s group. '
         'The response is paginated either by a limit/offset or page/size style. '
         'The style depends on the provided GET parameters. The properties of the '
         'returned rows depends on which fields the table has. For a complete '
         'overview of fields use the **list_database_table_fields** endpoint to '
         'list them all. In the example all field types are listed, but normally '
         'the number in field_{id} key is going to be the id of the field. '
         'The value is what the user has provided and the format of it depends on '
         'the fields type.\n'
         '\n'
         'The filters and sortings are automatically applied. To get a full '
         'overview of the applied filters and sortings you can use the '
         '`list_database_table_view_filters` and '
         '`list_database_table_view_sortings` endpoints.'),
        responses={
            200: example_pagination_row_serializer_class,
            400: get_error_schema(['ERROR_USER_NOT_IN_GROUP']),
            404: get_error_schema(['ERROR_GRID_DOES_NOT_EXIST'])
        })
    @map_exceptions({
        UserNotInGroupError: ERROR_USER_NOT_IN_GROUP,
        ViewDoesNotExist: ERROR_GRID_DOES_NOT_EXIST
    })
    @allowed_includes('field_options')
    def get(self, request, view_id, field_options):
        """
        Lists all the rows of a grid view, paginated either by a page or offset/limit.
        If the limit get parameter is provided the limit/offset pagination will be used
        else the page number pagination.

        Optionally the field options can also be included in the response if the the
        `field_options` are provided in the includes GET parameter.
        """

        view_handler = ViewHandler()
        view = view_handler.get_view(view_id, GridView)
        view.table.database.group.has_user(request.user, raise_error=True)

        model = view.table.get_model()
        queryset = model.objects.all().enhance_by_fields()

        # Applies the view filters and sortings to the queryset if there are any.
        queryset = view_handler.apply_filters(view, queryset)
        queryset = view_handler.apply_sorting(view, queryset)

        if 'count' in request.GET:
            return Response({'count': queryset.count()})

        if LimitOffsetPagination.limit_query_param in request.GET:
            paginator = LimitOffsetPagination()
        else:
            paginator = PageNumberPagination()

        page = paginator.paginate_queryset(queryset, request, self)
        serializer_class = get_row_serializer_class(model,
                                                    RowSerializer,
                                                    is_response=True)
        serializer = serializer_class(page, many=True)

        response = paginator.get_paginated_response(serializer.data)

        if field_options:
            # The serializer has the GridViewFieldOptionsField which fetches the
            # field options from the database and creates them if they don't exist,
            # but when added to the context the fields don't have to be fetched from
            # the database again when checking if they exist.
            context = {
                'fields': [o['field'] for o in model._field_objects.values()]
            }
            response.data.update(
                **GridViewSerializer(view, context=context).data)

        return response

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name='view_id',
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.INT,
                required=False,
                description=
                'Returns only rows that belong to the related view\'s '
                'table.')
        ],
        tags=['Database table grid view'],
        operation_id='filter_database_table_grid_view_rows',
        description=
        ('Lists only the rows and fields that match the request. Only the rows '
         'with the ids that are in the `row_ids` list are going to be returned. '
         'Same goes for the fields, only the fields with the ids in the '
         '`field_ids` are going to be returned. This endpoint could be used to '
         'refresh data after changes something. For example in the web frontend '
         'after changing a field type, the data of the related cells will be '
         'refreshed using this endpoint. In the example all field types are listed, '
         'but normally  the number in field_{id} key is going to be the id of the '
         'field. The value is what the user has provided and the format of it '
         'depends on the fields type.'),
        request=GridViewFilterSerializer,
        responses={
            200:
            get_example_row_serializer_class(True)(many=True),
            400:
            get_error_schema(
                ['ERROR_USER_NOT_IN_GROUP', 'ERROR_REQUEST_BODY_VALIDATION']),
            404:
            get_error_schema(['ERROR_GRID_DOES_NOT_EXIST'])
        })
    @map_exceptions({
        UserNotInGroupError: ERROR_USER_NOT_IN_GROUP,
        ViewDoesNotExist: ERROR_GRID_DOES_NOT_EXIST
    })
    @validate_body(GridViewFilterSerializer)
    def post(self, request, view_id, data):
        """
        Row filter endpoint that only lists the requested rows and optionally only the
        requested fields.
        """

        view = ViewHandler().get_view(view_id, GridView)
        view.table.database.group.has_user(request.user, raise_error=True)

        model = view.table.get_model(field_ids=data['field_ids'])
        results = model.objects.filter(pk__in=data['row_ids'])

        serializer_class = get_row_serializer_class(model,
                                                    RowSerializer,
                                                    is_response=True)
        serializer = serializer_class(results, many=True)
        return Response(serializer.data)

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name='view_id',
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.INT,
                required=False,
                description=
                'Updates the field related to the provided `view_id` '
                'parameter.')
        ],
        tags=['Database table grid view'],
        operation_id='update_database_table_grid_view_field_options',
        description=
        ('Updates the field options of a `grid` view. The field options are unique '
         'options per field for a view. This could for example be used to update '
         'the field width if the user changes it.'),
        request=GridViewSerializer,
        responses={
            200:
            GridViewSerializer,
            400:
            get_error_schema([
                'ERROR_USER_NOT_IN_GROUP', 'ERROR_UNRELATED_FIELD',
                'ERROR_REQUEST_BODY_VALIDATION'
            ]),
            404:
            get_error_schema(['ERROR_GRID_DOES_NOT_EXIST'])
        })
    @map_exceptions({
        UserNotInGroupError: ERROR_USER_NOT_IN_GROUP,
        ViewDoesNotExist: ERROR_GRID_DOES_NOT_EXIST,
        UnrelatedFieldError: ERROR_UNRELATED_FIELD
    })
    @validate_body(GridViewSerializer)
    def patch(self, request, view_id, data):
        """
        Updates the field options for the provided grid view.

        The following example body data will only update the width of the FIELD_ID
        and leaves the others untouched.
            {
                FIELD_ID: {
                    'width': 200
                }
            }
        """

        handler = ViewHandler()
        view = handler.get_view(view_id, GridView)
        handler.update_grid_view_field_options(request.user, view,
                                               data['field_options'])
        return Response(GridViewSerializer(view).data)
コード例 #3
0
class GridViewView(APIView):
    permission_classes = (IsAuthenticated,)

    def get_permissions(self):
        if self.request.method == "GET":
            return [AllowAny()]

        return super().get_permissions()

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name="view_id",
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.INT,
                description="Returns only rows that belong to the related view's "
                "table.",
            ),
            OpenApiParameter(
                name="count",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.NONE,
                description="If provided only the count will be returned.",
            ),
            OpenApiParameter(
                name="include",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description=(
                    "Can contain `field_options` which will add an object with the "
                    "same name to the response if included. That object contains "
                    "user defined view settings for each field. For example the "
                    "field's width is included in here."
                ),
            ),
            OpenApiParameter(
                name="limit",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Defines how many rows should be returned.",
            ),
            OpenApiParameter(
                name="offset",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Can only be used in combination with the `limit` "
                "parameter and defines from which offset the rows should "
                "be returned.",
            ),
            OpenApiParameter(
                name="page",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Defines which page of rows should be returned. Either "
                "the `page` or `limit` can be provided, not both.",
            ),
            OpenApiParameter(
                name="size",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.INT,
                description="Can only be used in combination with the `page` parameter "
                "and defines how many rows should be returned.",
            ),
            OpenApiParameter(
                name="search",
                location=OpenApiParameter.QUERY,
                type=OpenApiTypes.STR,
                description="If provided only rows with data that matches the search "
                "query are going to be returned.",
            ),
        ],
        tags=["Database table grid view"],
        operation_id="list_database_table_grid_view_rows",
        description=(
            "Lists the requested rows of the view's table related to the provided "
            "`view_id` if the authorized user has access to the database's group. "
            "The response is paginated either by a limit/offset or page/size style. "
            "The style depends on the provided GET parameters. The properties of the "
            "returned rows depends on which fields the table has. For a complete "
            "overview of fields use the **list_database_table_fields** endpoint to "
            "list them all. In the example all field types are listed, but normally "
            "the number in field_{id} key is going to be the id of the field. "
            "The value is what the user has provided and the format of it depends on "
            "the fields type.\n"
            "\n"
            "The filters and sortings are automatically applied. To get a full "
            "overview of the applied filters and sortings you can use the "
            "`list_database_table_view_filters` and "
            "`list_database_table_view_sortings` endpoints."
        ),
        responses={
            200: example_pagination_row_serializer_class_with_field_options,
            400: get_error_schema(["ERROR_USER_NOT_IN_GROUP"]),
            404: get_error_schema(["ERROR_GRID_DOES_NOT_EXIST"]),
        },
    )
    @map_exceptions(
        {
            UserNotInGroup: ERROR_USER_NOT_IN_GROUP,
            ViewDoesNotExist: ERROR_GRID_DOES_NOT_EXIST,
        }
    )
    @allowed_includes("field_options")
    def get(self, request, view_id, field_options):
        """
        Lists all the rows of a grid view, paginated either by a page or offset/limit.
        If the limit get parameter is provided the limit/offset pagination will be used
        else the page number pagination.

        Optionally the field options can also be included in the response if the the
        `field_options` are provided in the include GET parameter.
        """

        search = request.GET.get("search")

        view_handler = ViewHandler()
        view = view_handler.get_view(view_id, GridView)

        view.table.database.group.has_user(
            request.user, raise_error=True, allow_if_template=True
        )
        model = view.table.get_model()
        queryset = view_handler.get_queryset(view, search, model)

        if "count" in request.GET:
            return Response({"count": queryset.count()})

        if LimitOffsetPagination.limit_query_param in request.GET:
            paginator = LimitOffsetPagination()
        else:
            paginator = PageNumberPagination()

        page = paginator.paginate_queryset(queryset, request, self)
        serializer_class = get_row_serializer_class(
            model, RowSerializer, is_response=True
        )
        serializer = serializer_class(page, many=True)

        response = paginator.get_paginated_response(serializer.data)

        if field_options:
            # The serializer has the GridViewFieldOptionsField which fetches the
            # field options from the database and creates them if they don't exist,
            # but when added to the context the fields don't have to be fetched from
            # the database again when checking if they exist.
            context = {"fields": [o["field"] for o in model._field_objects.values()]}
            serialized_view = GridViewSerializer(view, context=context).data
            response.data["field_options"] = serialized_view["field_options"]

        return response

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name="view_id",
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.INT,
                required=False,
                description="Returns only rows that belong to the related view's "
                "table.",
            )
        ],
        tags=["Database table grid view"],
        operation_id="filter_database_table_grid_view_rows",
        description=(
            "Lists only the rows and fields that match the request. Only the rows "
            "with the ids that are in the `row_ids` list are going to be returned. "
            "Same goes for the fields, only the fields with the ids in the "
            "`field_ids` are going to be returned. This endpoint could be used to "
            "refresh data after changes something. For example in the web frontend "
            "after changing a field type, the data of the related cells will be "
            "refreshed using this endpoint. In the example all field types are listed, "
            "but normally  the number in field_{id} key is going to be the id of the "
            "field. The value is what the user has provided and the format of it "
            "depends on the fields type."
        ),
        request=GridViewFilterSerializer,
        responses={
            200: get_example_row_serializer_class(True)(many=True),
            400: get_error_schema(
                ["ERROR_USER_NOT_IN_GROUP", "ERROR_REQUEST_BODY_VALIDATION"]
            ),
            404: get_error_schema(["ERROR_GRID_DOES_NOT_EXIST"]),
        },
    )
    @map_exceptions(
        {
            UserNotInGroup: ERROR_USER_NOT_IN_GROUP,
            ViewDoesNotExist: ERROR_GRID_DOES_NOT_EXIST,
        }
    )
    @validate_body(GridViewFilterSerializer)
    def post(self, request, view_id, data):
        """
        Row filter endpoint that only lists the requested rows and optionally only the
        requested fields.
        """

        view = ViewHandler().get_view(view_id, GridView)
        view.table.database.group.has_user(request.user, raise_error=True)

        model = view.table.get_model(field_ids=data["field_ids"])
        results = model.objects.filter(pk__in=data["row_ids"])

        serializer_class = get_row_serializer_class(
            model, RowSerializer, is_response=True
        )
        serializer = serializer_class(results, many=True)
        return Response(serializer.data)

    @extend_schema(
        parameters=[
            OpenApiParameter(
                name="view_id",
                location=OpenApiParameter.PATH,
                type=OpenApiTypes.INT,
                required=False,
                description="Updates the field related to the provided `view_id` "
                "parameter.",
            )
        ],
        tags=["Database table grid view"],
        operation_id="update_database_table_grid_view_field_options",
        description=(
            "Updates the field options of a `grid` view. The field options are unique "
            "options per field for a view. This could for example be used to update "
            "the field width if the user changes it."
        ),
        request=GridViewSerializer,
        responses={
            200: GridViewSerializer,
            400: get_error_schema(
                [
                    "ERROR_USER_NOT_IN_GROUP",
                    "ERROR_UNRELATED_FIELD",
                    "ERROR_REQUEST_BODY_VALIDATION",
                ]
            ),
            404: get_error_schema(["ERROR_GRID_DOES_NOT_EXIST"]),
        },
    )
    @map_exceptions(
        {
            UserNotInGroup: ERROR_USER_NOT_IN_GROUP,
            ViewDoesNotExist: ERROR_GRID_DOES_NOT_EXIST,
            UnrelatedFieldError: ERROR_UNRELATED_FIELD,
        }
    )
    @validate_body(GridViewSerializer)
    def patch(self, request, view_id, data):
        """
        Updates the field options for the provided grid view.

        The following example body data will only update the width of the FIELD_ID
        and leaves the others untouched.
            {
                FIELD_ID: {
                    'width': 200
                }
            }
        """

        handler = ViewHandler()
        view = handler.get_view(view_id, GridView)
        handler.update_grid_view_field_options(
            request.user, view, data["field_options"]
        )
        return Response(GridViewSerializer(view).data)