예제 #1
0
파일: views.py 프로젝트: code-watch/baserow
    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 = 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 search:
            queryset = queryset.search_all_fields(search)

        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
예제 #2
0
def row_updated(sender, row, user, table, model, **kwargs):
    table_page_type = page_registry.get('table')
    transaction.on_commit(lambda: table_page_type.broadcast(
        {
            'type':
            'row_updated',
            'table_id':
            table.id,
            'row':
            get_row_serializer_class(model, RowSerializer, is_response=True)
            (row).data
        },
        getattr(user, 'web_socket_id', None),
        table_id=table.id))
예제 #3
0
    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(request.user, view_id, GridView)

        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)
예제 #4
0
def row_created(sender, row, before, user, table, model, **kwargs):
    table_page_type = page_registry.get("table")
    transaction.on_commit(
        lambda: table_page_type.broadcast(
            {
                "type": "row_created",
                "table_id": table.id,
                "row": get_row_serializer_class(model, RowSerializer, is_response=True)(
                    row
                ).data,
                "before_row_id": before.id if before else None,
            },
            getattr(user, "web_socket_id", None),
            table_id=table.id,
        )
    )
예제 #5
0
def row_updated(sender, row, user, table, model, before_return, **kwargs):
    table_page_type = page_registry.get("table")
    transaction.on_commit(
        lambda: table_page_type.broadcast(
            {
                "type": "row_updated",
                "table_id": table.id,
                # The web-frontend expects a serialized version of the row before it
                # was updated in order the estimate what position the row had in the
                # view.
                "row_before_update": dict(before_return)[before_row_update],
                "row": get_row_serializer_class(model, RowSerializer, is_response=True)(
                    row
                ).data,
            },
            getattr(user, "web_socket_id", None),
            table_id=table.id,
        )
    )
예제 #6
0
    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 = ViewHandler().get_view(request.user, view_id, GridView)

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

        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
def test_get_table_serializer(data_fixture):
    table = data_fixture.create_database_table(name='Cars')
    table_2 = data_fixture.create_database_table()
    data_fixture.create_text_field(table=table,
                                   order=0,
                                   name='Color',
                                   text_default='white')
    data_fixture.create_number_field(table=table, order=1, name='Horsepower')
    data_fixture.create_boolean_field(table=table, order=2, name='For sale')
    data_fixture.create_number_field(table=table,
                                     order=2,
                                     name='Price',
                                     number_type='DECIMAL',
                                     number_negative=True,
                                     number_decimal_places=2)

    model = table.get_model(attribute_names=True)
    serializer_class = get_row_serializer_class(model=model)

    # expect the result to be empty if not provided
    serializer_instance = serializer_class(data={})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {
        'color': 'white',
        'horsepower': None,
        'for_sale': False,
        'price': None
    }

    # text field
    serializer_instance = serializer_class(data={'color': 'Green'})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['color'] == 'Green'

    serializer_instance = serializer_class(data={'color': 123})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['color'] == '123'

    serializer_instance = serializer_class(data={'color': None})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['color'] == None

    # number field
    serializer_instance = serializer_class(data={'horsepower': 120})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['horsepower'] == 120

    serializer_instance = serializer_class(data={'horsepower': None})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['horsepower'] == None

    serializer_instance = serializer_class(data={'horsepower': 'abc'})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors['horsepower']) == 1

    serializer_instance = serializer_class(data={'horsepower': -1})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors['horsepower']) == 1

    # boolean field
    serializer_instance = serializer_class(data={'for_sale': True})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['for_sale'] == True

    serializer_instance = serializer_class(data={'for_sale': False})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['for_sale'] == False

    serializer_instance = serializer_class(data={'for_sale': None})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors['for_sale']) == 1

    serializer_instance = serializer_class(data={'for_sale': 'abc'})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors['for_sale']) == 1

    # price field
    serializer_instance = serializer_class(data={'price': 120})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['price'] == '120.00'

    serializer_instance = serializer_class(data={'price': '-10.22'})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['price'] == '-10.22'

    serializer_instance = serializer_class(data={'price': 'abc'})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors['price']) == 1

    serializer_instance = serializer_class(data={'price': None})
    assert serializer_instance.is_valid()
    assert serializer_instance.data['price'] == None

    # not existing value
    serializer_instance = serializer_class(data={'NOT_EXISTING': True})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {
        'color': 'white',
        'horsepower': None,
        'for_sale': False,
        'price': None
    }

    # all fields
    serializer_instance = serializer_class(data={
        'color': 'green',
        'horsepower': 120,
        'for_sale': True,
        'price': 120.22
    })
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {
        'color': 'green',
        'horsepower': 120,
        'for_sale': True,
        'price': '120.22'
    }

    # adding an extra field and only use that one.
    price_field = data_fixture.create_number_field(table=table_2,
                                                   order=0,
                                                   name='Sale price',
                                                   number_type='DECIMAL',
                                                   number_decimal_places=3,
                                                   number_negative=True)
    model = table.get_model(fields=[price_field], field_ids=[])
    serializer_class = get_row_serializer_class(model=model)

    serializer_instance = serializer_class(
        data={f'field_{price_field.id}': 12.22})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {f'field_{price_field.id}': '12.220'}

    serializer_instance = serializer_class(
        data={f'field_{price_field.id}': -10.02})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {f'field_{price_field.id}': '-10.020'}

    serializer_instance = serializer_class(
        data={f'field_{price_field.id}': 'abc'})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors[f'field_{price_field.id}']) == 1
예제 #8
0
def test_primary_single_select_field_with_link_row_field(
        api_client, data_fixture, django_assert_num_queries):
    """
    We expect the relation to a table that has a single select field to work.
    """

    user, token = data_fixture.create_user_and_token()
    database = data_fixture.create_database_application(user=user,
                                                        name='Placeholder')
    example_table = data_fixture.create_database_table(name='Example',
                                                       database=database)
    customers_table = data_fixture.create_database_table(name='Customers',
                                                         database=database)

    field_handler = FieldHandler()
    row_handler = RowHandler()

    data_fixture.create_text_field(name='Name',
                                   table=example_table,
                                   primary=True)
    customers_primary = field_handler.create_field(user=user,
                                                   table=customers_table,
                                                   type_name='single_select',
                                                   select_options=[{
                                                       'value':
                                                       'Option 1',
                                                       'color':
                                                       'red'
                                                   }, {
                                                       'value':
                                                       'Option 2',
                                                       'color':
                                                       'blue'
                                                   }, {
                                                       'value':
                                                       'Option 3',
                                                       'color':
                                                       'orange'
                                                   }],
                                                   primary=True)
    link_row_field = field_handler.create_field(user=user,
                                                table=example_table,
                                                type_name='link_row',
                                                link_row_table=customers_table)
    select_options = customers_primary.select_options.all()

    customers_row_1 = row_handler.create_row(
        user=user,
        table=customers_table,
        values={f'field_{customers_primary.id}': select_options[0].id})
    customers_row_2 = row_handler.create_row(
        user=user,
        table=customers_table,
        values={f'field_{customers_primary.id}': select_options[1].id})
    customers_row_3 = row_handler.create_row(
        user=user,
        table=customers_table,
        values={f'field_{customers_primary.id}': select_options[2].id})
    row_handler.create_row(user,
                           table=example_table,
                           values={
                               f'field_{link_row_field.id}':
                               [customers_row_1.id, customers_row_2.id]
                           })
    row_handler.create_row(
        user,
        table=example_table,
        values={f'field_{link_row_field.id}': [customers_row_1.id]})
    row_handler.create_row(
        user,
        table=example_table,
        values={f'field_{link_row_field.id}': [customers_row_3.id]})

    model = example_table.get_model()
    queryset = model.objects.all().enhance_by_fields()
    serializer_class = get_row_serializer_class(model,
                                                RowSerializer,
                                                is_response=True)

    with django_assert_num_queries(3):
        serializer = serializer_class(queryset, many=True)
        serializer.data

    response = api_client.get(reverse('api:database:rows:list',
                                      kwargs={'table_id': example_table.id}),
                              format='json',
                              HTTP_AUTHORIZATION=f'JWT {token}')
    response_json = response.json()

    assert (response_json['results'][0][f'field_{link_row_field.id}'][0]
            ['value'] == 'Option 1')
    assert (response_json['results'][0][f'field_{link_row_field.id}'][1]
            ['value'] == 'Option 2')
    assert (response_json['results'][1][f'field_{link_row_field.id}'][0]
            ['value'] == 'Option 1')
    assert (response_json['results'][2][f'field_{link_row_field.id}'][0]
            ['value'] == 'Option 3')
def test_primary_single_select_field_with_link_row_field(
        api_client, data_fixture, django_assert_num_queries):
    """
    We expect the relation to a table that has a single select field to work.
    """

    user, token = data_fixture.create_user_and_token()
    database = data_fixture.create_database_application(user=user,
                                                        name="Placeholder")
    example_table = data_fixture.create_database_table(name="Example",
                                                       database=database)
    customers_table = data_fixture.create_database_table(name="Customers",
                                                         database=database)

    field_handler = FieldHandler()
    row_handler = RowHandler()

    data_fixture.create_text_field(name="Name",
                                   table=example_table,
                                   primary=True)
    customers_primary = field_handler.create_field(
        user=user,
        table=customers_table,
        type_name="single_select",
        select_options=[
            {
                "value": "Option 1",
                "color": "red"
            },
            {
                "value": "Option 2",
                "color": "blue"
            },
            {
                "value": "Option 3",
                "color": "orange"
            },
        ],
        primary=True,
    )
    link_row_field = field_handler.create_field(
        user=user,
        table=example_table,
        type_name="link_row",
        link_row_table=customers_table,
    )
    select_options = customers_primary.select_options.all()

    customers_row_1 = row_handler.create_row(
        user=user,
        table=customers_table,
        values={f"field_{customers_primary.id}": select_options[0].id},
    )
    customers_row_2 = row_handler.create_row(
        user=user,
        table=customers_table,
        values={f"field_{customers_primary.id}": select_options[1].id},
    )
    customers_row_3 = row_handler.create_row(
        user=user,
        table=customers_table,
        values={f"field_{customers_primary.id}": select_options[2].id},
    )
    row_handler.create_row(
        user,
        table=example_table,
        values={
            f"field_{link_row_field.id}":
            [customers_row_1.id, customers_row_2.id]
        },
    )
    row_handler.create_row(
        user,
        table=example_table,
        values={f"field_{link_row_field.id}": [customers_row_1.id]},
    )
    row_handler.create_row(
        user,
        table=example_table,
        values={f"field_{link_row_field.id}": [customers_row_3.id]},
    )

    model = example_table.get_model()
    queryset = model.objects.all().enhance_by_fields()
    serializer_class = get_row_serializer_class(model,
                                                RowSerializer,
                                                is_response=True)

    with django_assert_num_queries(3):
        serializer = serializer_class(queryset, many=True)
        serializer.data

    response = api_client.get(
        reverse("api:database:rows:list",
                kwargs={"table_id": example_table.id}),
        format="json",
        HTTP_AUTHORIZATION=f"JWT {token}",
    )
    response_json = response.json()

    assert (response_json["results"][0][f"field_{link_row_field.id}"][0]
            ["value"] == "Option 1")
    assert (response_json["results"][0][f"field_{link_row_field.id}"][1]
            ["value"] == "Option 2")
    assert (response_json["results"][1][f"field_{link_row_field.id}"][0]
            ["value"] == "Option 1")
    assert (response_json["results"][2][f"field_{link_row_field.id}"][0]
            ["value"] == "Option 3")
예제 #10
0
def test_get_table_serializer(data_fixture):
    table = data_fixture.create_database_table(name="Cars")
    table_2 = data_fixture.create_database_table()
    text_field = data_fixture.create_text_field(table=table,
                                                order=0,
                                                name="Color",
                                                text_default="white")
    data_fixture.create_number_field(table=table, order=1, name="Horsepower")
    data_fixture.create_boolean_field(table=table, order=3, name="For sale")
    data_fixture.create_number_field(
        table=table,
        order=4,
        name="Price",
        number_type="DECIMAL",
        number_negative=True,
        number_decimal_places=2,
    )

    model = table.get_model(attribute_names=True)
    serializer_class = get_row_serializer_class(model=model)

    # expect the result to be empty if not provided
    serializer_instance = serializer_class(data={})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {
        "color": "white",
        "horsepower": None,
        "for_sale": False,
        "price": None,
    }

    # text field
    serializer_instance = serializer_class(data={"color": "Green"})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["color"] == "Green"

    serializer_instance = serializer_class(data={"color": 123})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["color"] == "123"

    serializer_instance = serializer_class(data={"color": None})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["color"] is None

    # number field
    serializer_instance = serializer_class(data={"horsepower": 120})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["horsepower"] == "120"

    serializer_instance = serializer_class(
        data={
            "horsepower": 99999999999999999999999999999999999999999999999999
        })
    assert serializer_instance.is_valid()
    assert (serializer_instance.data["horsepower"] ==
            "99999999999999999999999999999999999999999999999999")

    serializer_instance = serializer_class(
        data={
            "horsepower": 999999999999999999999999999999999999999999999999999
        })
    assert not serializer_instance.is_valid()

    serializer_instance = serializer_class(data={"horsepower": None})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["horsepower"] is None

    serializer_instance = serializer_class(data={"horsepower": "abc"})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors["horsepower"]) == 1

    serializer_instance = serializer_class(data={"horsepower": -1})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors["horsepower"]) == 1

    # boolean field
    serializer_instance = serializer_class(data={"for_sale": True})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["for_sale"] is True

    serializer_instance = serializer_class(data={"for_sale": False})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["for_sale"] is False

    serializer_instance = serializer_class(data={"for_sale": None})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors["for_sale"]) == 1

    serializer_instance = serializer_class(data={"for_sale": "abc"})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors["for_sale"]) == 1

    # price field
    serializer_instance = serializer_class(data={"price": 120})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["price"] == "120.00"

    serializer_instance = serializer_class(data={"price": "-10.22"})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["price"] == "-10.22"

    serializer_instance = serializer_class(data={"price": "abc"})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors["price"]) == 1

    serializer_instance = serializer_class(data={"price": None})
    assert serializer_instance.is_valid()
    assert serializer_instance.data["price"] is None

    # not existing value
    serializer_instance = serializer_class(data={"NOT_EXISTING": True})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {
        "color": "white",
        "horsepower": None,
        "for_sale": False,
        "price": None,
    }

    # all fields
    serializer_instance = serializer_class(data={
        "color": "green",
        "horsepower": 120,
        "for_sale": True,
        "price": 120.22
    })
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {
        "color": "green",
        "horsepower": "120",
        "for_sale": True,
        "price": "120.22",
    }

    # adding an extra field and only use that one.
    price_field = data_fixture.create_number_field(
        table=table_2,
        order=0,
        name="Sale price",
        number_type="DECIMAL",
        number_decimal_places=3,
        number_negative=True,
    )
    model = table.get_model(fields=[price_field], field_ids=[])
    serializer_class = get_row_serializer_class(model=model)

    serializer_instance = serializer_class(
        data={f"field_{price_field.id}": 12.22})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {f"field_{price_field.id}": "12.220"}

    serializer_instance = serializer_class(
        data={f"field_{price_field.id}": -10.02})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {f"field_{price_field.id}": "-10.020"}

    serializer_instance = serializer_class(
        data={f"field_{price_field.id}": "abc"})
    assert not serializer_instance.is_valid()
    assert len(serializer_instance.errors[f"field_{price_field.id}"]) == 1

    model = table.get_model(attribute_names=True)
    serializer_class = get_row_serializer_class(model=model,
                                                field_ids=[text_field.id])
    serializer_instance = serializer_class(data={})
    assert serializer_instance.is_valid()
    assert serializer_instance.data == {"color": "white"}
예제 #11
0
def before_row_delete(sender, row, user, table, model, **kwargs):
    # Generate a serialized version of the row before it is deleted. The
    # `row_deleted` receiver needs this serialized version because it can't serialize
    # the row after is has been deleted.
    return get_row_serializer_class(model, RowSerializer, is_response=True)(row).data