1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-14 17:18:33 +00:00

Refactor number field

This commit is contained in:
Petr Stribny 2022-02-22 16:24:14 +00:00
parent 7f5dc1c390
commit 704ab3be2f
52 changed files with 256 additions and 382 deletions

View file

@ -1,4 +1,5 @@
from django.utils.functional import lazy from django.utils.functional import lazy
from django.core.exceptions import ValidationError
from drf_spectacular.types import OpenApiTypes from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers from rest_framework import serializers
@ -168,3 +169,17 @@ class FileFieldResponseSerializer(
def get_instance_attr(self, instance, name): def get_instance_attr(self, instance, name):
return instance[name] return instance[name]
class MustBeEmptyField(serializers.Field):
def __init__(self, error_message, *args, **kwargs):
def validator(value):
raise ValidationError(error_message, code="invalid")
kwargs["write_only"] = True
kwargs["required"] = False
kwargs["validators"] = [validator]
super().__init__(*args, **kwargs)
def to_internal_value(self, data):
return None

View file

@ -18,21 +18,25 @@ def construct_all_possible_field_kwargs(
"url": [{"name": "url"}], "url": [{"name": "url"}],
"email": [{"name": "email"}], "email": [{"name": "email"}],
"number": [ "number": [
{"name": "negative_int", "number_type": "INTEGER", "number_negative": True}, {
"name": "negative_int",
"number_negative": True,
"number_decimal_places": 0,
},
{ {
"name": "positive_int", "name": "positive_int",
"number_type": "INTEGER",
"number_negative": False, "number_negative": False,
"number_decimal_places": 0,
}, },
{ {
"name": "negative_decimal", "name": "negative_decimal",
"number_type": "DECIMAL",
"number_negative": "True", "number_negative": "True",
"number_decimal_places": 1,
}, },
{ {
"name": "positive_decimal", "name": "positive_decimal",
"number_type": "DECIMAL",
"number_negative": False, "number_negative": False,
"number_decimal_places": 1,
}, },
], ],
"rating": [ "rating": [

View file

@ -37,6 +37,7 @@ from baserow.contrib.database.api.fields.serializers import (
FileFieldRequestSerializer, FileFieldRequestSerializer,
SelectOptionSerializer, SelectOptionSerializer,
FileFieldResponseSerializer, FileFieldResponseSerializer,
MustBeEmptyField,
) )
from baserow.contrib.database.formula import ( from baserow.contrib.database.formula import (
BaserowExpression, BaserowExpression,
@ -82,8 +83,6 @@ from .fields import (
) )
from .handler import FieldHandler from .handler import FieldHandler
from .models import ( from .models import (
NUMBER_TYPE_INTEGER,
NUMBER_TYPE_DECIMAL,
TextField, TextField,
LongTextField, LongTextField,
URLField, URLField,
@ -315,8 +314,15 @@ class NumberFieldType(FieldType):
type = "number" type = "number"
model_class = NumberField model_class = NumberField
allowed_fields = ["number_type", "number_decimal_places", "number_negative"] allowed_fields = ["number_decimal_places", "number_negative"]
serializer_field_names = ["number_type", "number_decimal_places", "number_negative"] serializer_field_names = ["number_decimal_places", "number_negative", "number_type"]
serializer_field_overrides = {
"number_type": MustBeEmptyField(
"The number_type option has been removed and can no longer be provided. "
"Instead set number_decimal_places to 0 for an integer or 1-5 for a "
"decimal."
)
}
def prepare_value_for_db(self, instance, value): def prepare_value_for_db(self, instance, value):
if value is not None: if value is not None:
@ -331,11 +337,7 @@ class NumberFieldType(FieldType):
def get_serializer_field(self, instance, **kwargs): def get_serializer_field(self, instance, **kwargs):
required = kwargs.get("required", False) required = kwargs.get("required", False)
kwargs["decimal_places"] = ( kwargs["decimal_places"] = instance.number_decimal_places
0
if instance.number_type == NUMBER_TYPE_INTEGER
else instance.number_decimal_places
)
if not instance.number_negative: if not instance.number_negative:
kwargs["min_value"] = 0 kwargs["min_value"] = 0
@ -357,7 +359,7 @@ class NumberFieldType(FieldType):
# don't convert it to a string. However if a decimal to preserve any precision # don't convert it to a string. However if a decimal to preserve any precision
# we keep it as a string. # we keep it as a string.
instance = field_object["field"] instance = field_object["field"]
if instance.number_type == NUMBER_TYPE_INTEGER: if instance.number_decimal_places == 0:
return int(value) return int(value)
# DRF's Decimal Serializer knows how to quantize and format the decimal # DRF's Decimal Serializer knows how to quantize and format the decimal
@ -365,11 +367,7 @@ class NumberFieldType(FieldType):
return self.get_serializer_field(instance).to_representation(value) return self.get_serializer_field(instance).to_representation(value)
def get_model_field(self, instance, **kwargs): def get_model_field(self, instance, **kwargs):
kwargs["decimal_places"] = ( kwargs["decimal_places"] = instance.number_decimal_places
0
if instance.number_type == NUMBER_TYPE_INTEGER
else instance.number_decimal_places
)
return models.DecimalField( return models.DecimalField(
max_digits=self.MAX_DIGITS + kwargs["decimal_places"], max_digits=self.MAX_DIGITS + kwargs["decimal_places"],
@ -379,13 +377,13 @@ class NumberFieldType(FieldType):
) )
def random_value(self, instance, fake, cache): def random_value(self, instance, fake, cache):
if instance.number_type == NUMBER_TYPE_INTEGER: if instance.number_decimal_places == 0:
return fake.pyint( return fake.pyint(
min_value=-10000 if instance.number_negative else 1, min_value=-10000 if instance.number_negative else 1,
max_value=10000, max_value=10000,
step=1, step=1,
) )
elif instance.number_type == NUMBER_TYPE_DECIMAL: elif instance.number_decimal_places > 0:
return fake.pydecimal( return fake.pydecimal(
min_value=-10000 if instance.number_negative else 1, min_value=-10000 if instance.number_negative else 1,
max_value=10000, max_value=10000,
@ -394,9 +392,7 @@ class NumberFieldType(FieldType):
def get_alter_column_prepare_new_value(self, connection, from_field, to_field): def get_alter_column_prepare_new_value(self, connection, from_field, to_field):
if connection.vendor == "postgresql": if connection.vendor == "postgresql":
decimal_places = 0 decimal_places = to_field.number_decimal_places
if to_field.number_type == NUMBER_TYPE_DECIMAL:
decimal_places = to_field.number_decimal_places
function = f"round(p_in::numeric, {decimal_places})" function = f"round(p_in::numeric, {decimal_places})"
@ -420,21 +416,14 @@ class NumberFieldType(FieldType):
return value if value is None else str(value) return value if value is None else str(value)
def to_baserow_formula_type(self, field: NumberField) -> BaserowFormulaType: def to_baserow_formula_type(self, field: NumberField) -> BaserowFormulaType:
if field.number_type == NUMBER_TYPE_INTEGER: return BaserowFormulaNumberType(
number_decimal_places = 0 number_decimal_places=field.number_decimal_places
else: )
number_decimal_places = field.number_decimal_places
return BaserowFormulaNumberType(number_decimal_places=number_decimal_places)
def from_baserow_formula_type( def from_baserow_formula_type(
self, formula_type: BaserowFormulaNumberType self, formula_type: BaserowFormulaNumberType
) -> NumberField: ) -> NumberField:
if formula_type.number_decimal_places == 0:
number_type = NUMBER_TYPE_INTEGER
else:
number_type = NUMBER_TYPE_DECIMAL
return NumberField( return NumberField(
number_type=number_type,
number_decimal_places=formula_type.number_decimal_places, number_decimal_places=formula_type.number_decimal_places,
number_negative=True, number_negative=True,
) )

View file

@ -2,7 +2,6 @@ from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from baserow.contrib.database.fields.mixins import ( from baserow.contrib.database.fields.mixins import (
BaseDateMixin, BaseDateMixin,
TimezoneMixin, TimezoneMixin,
@ -26,16 +25,11 @@ from baserow.core.mixins import (
) )
from baserow.core.utils import to_snake_case, remove_special_characters from baserow.core.utils import to_snake_case, remove_special_characters
NUMBER_TYPE_INTEGER = "INTEGER"
NUMBER_TYPE_DECIMAL = "DECIMAL"
NUMBER_TYPE_CHOICES = (
("INTEGER", "Integer"),
("DECIMAL", "Decimal"),
)
NUMBER_MAX_DECIMAL_PLACES = 5 NUMBER_MAX_DECIMAL_PLACES = 5
NUMBER_DECIMAL_PLACES_CHOICES = [ NUMBER_DECIMAL_PLACES_CHOICES = [
(0, "1"),
(1, "1.0"), (1, "1.0"),
(2, "1.00"), (2, "1.00"),
(3, "1.000"), (3, "1.000"),
@ -206,12 +200,9 @@ class URLField(Field):
class NumberField(Field): class NumberField(Field):
number_type = models.CharField(
max_length=32, choices=NUMBER_TYPE_CHOICES, default=NUMBER_TYPE_INTEGER
)
number_decimal_places = models.IntegerField( number_decimal_places = models.IntegerField(
choices=NUMBER_DECIMAL_PLACES_CHOICES, choices=NUMBER_DECIMAL_PLACES_CHOICES,
default=1, default=0,
help_text="The amount of digits allowed after the point.", help_text="The amount of digits allowed after the point.",
) )
number_negative = models.BooleanField( number_negative = models.BooleanField(
@ -219,10 +210,8 @@ class NumberField(Field):
) )
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
"""Check if the number_type and number_decimal_places has a valid choice.""" """Check if the number_decimal_places has a valid choice."""
if not any(self.number_type in _tuple for _tuple in NUMBER_TYPE_CHOICES):
raise ValueError(f"{self.number_type} is not a valid choice.")
if not any( if not any(
self.number_decimal_places in _tuple self.number_decimal_places in _tuple
for _tuple in NUMBER_DECIMAL_PLACES_CHOICES for _tuple in NUMBER_DECIMAL_PLACES_CHOICES
@ -396,7 +385,7 @@ class FormulaField(Field):
null=True, null=True,
) )
number_decimal_places = models.IntegerField( number_decimal_places = models.IntegerField(
choices=[(0, "1")] + NUMBER_DECIMAL_PLACES_CHOICES, choices=NUMBER_DECIMAL_PLACES_CHOICES,
default=None, default=None,
null=True, null=True,
help_text="The amount of digits allowed after the point.", help_text="The amount of digits allowed after the point.",

View file

@ -1,7 +1,6 @@
# We need to change all NumberFields that are Integers to use DecimalField in Django # We need to change all NumberFields that are Integers to use DecimalField in Django
# and NUMERIC(50, 0) in Postgres. This migration converts all the existing Integer data # and NUMERIC(50, 0) in Postgres. This migration converts all the existing Integer data
# types in fields to Decimal. # types in fields to Decimal.
from baserow.contrib.database.fields.models import NUMBER_TYPE_INTEGER
from django.db import migrations, connection from django.db import migrations, connection
from baserow.contrib.database.fields.models import Field as FieldModel from baserow.contrib.database.fields.models import Field as FieldModel
@ -25,7 +24,7 @@ def forward(apps, schema_editor):
# which could result in an out of memory exception. # which could result in an out of memory exception.
tables_schema_editor.atomic.__exit__(None, None, None) tables_schema_editor.atomic.__exit__(None, None, None)
for field in NumberField.objects.filter(number_type=NUMBER_TYPE_INTEGER): for field in NumberField.objects.filter(number_type="INTEGER"):
table_name = f"database_table_{field.table.id}" table_name = f"database_table_{field.table.id}"
column_name = FieldModel.db_column.__get__(field, FieldModel) column_name = FieldModel.db_column.__get__(field, FieldModel)
sql = alter_sql(tables_schema_editor, table_name, column_name) sql = alter_sql(tables_schema_editor, table_name, column_name)

View file

@ -0,0 +1,29 @@
# Generated by Django 3.2.6 on 2022-02-14 13:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("database", "0060_set_ordering_on_tablewebhook_models"),
]
operations = [
migrations.AlterField(
model_name="numberfield",
name="number_decimal_places",
field=models.IntegerField(
choices=[
(0, "1"),
(1, "1.0"),
(2, "1.00"),
(3, "1.000"),
(4, "1.0000"),
(5, "1.00000"),
],
default=0,
help_text="The amount of digits allowed after the point.",
),
),
]

View file

@ -0,0 +1,29 @@
from django.db import migrations
def forward(apps, schema_editor):
"""
If the NumberField.number_type was decimal we keep the decimal places
intact.
If the NumberField.number_type was integer we set the decimal places to
0 as the number field could have any number of decimal places set before.
"""
NumberField = apps.get_model("database", "NumberField")
NumberField.objects.filter(number_type="INTEGER").update(number_decimal_places=0)
def reverse(apps, schema_editor):
...
class Migration(migrations.Migration):
dependencies = [
("database", "0061_change_decimal_places"),
]
operations = [
migrations.RunPython(forward, reverse),
]

View file

@ -0,0 +1,17 @@
# Generated by Django 3.2.6 on 2022-02-14 13:28
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("database", "0062_migrate_number_type"),
]
operations = [
migrations.RemoveField(
model_name="numberfield",
name="number_type",
),
]

View file

@ -59,7 +59,6 @@ def setup_interesting_test_table(data_fixture, user_kwargs=None):
table=decimal_link_table, table=decimal_link_table,
name="text_field", name="text_field",
primary=True, primary=True,
number_type="DECIMAL",
number_decimal_places=3, number_decimal_places=3,
number_negative=True, number_negative=True,
) )

View file

@ -71,8 +71,7 @@
"name": "Walkability", "name": "Walkability",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -81,8 +80,7 @@
"name": "Transit", "name": "Transit",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -98,8 +96,7 @@
"name": "Built", "name": "Built",
"order": 9, "order": 9,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1044,8 +1041,7 @@
"name": "Bathrooms", "name": "Bathrooms",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1054,8 +1050,7 @@
"name": "Bedrooms", "name": "Bedrooms",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1064,8 +1059,7 @@
"name": "Rent", "name": "Rent",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1179,8 +1173,7 @@
"name": "Size (m\u00b2)", "name": "Size (m\u00b2)",
"order": 14, "order": 14,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -2480,8 +2473,7 @@
"name": "Zip Code", "name": "Zip Code",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -64,8 +64,7 @@
"name": "Duration (minutes)", "name": "Duration (minutes)",
"order": 3, "order": 3,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -1310,8 +1310,7 @@
"name": "Channel Rating (1-5)", "name": "Channel Rating (1-5)",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -148,8 +148,7 @@
"name": "Pages", "name": "Pages",
"order": 10, "order": 10,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
} }
], ],

View file

@ -86,8 +86,7 @@
"name": "Word Count", "name": "Word Count",
"order": 11, "order": 11,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -261,8 +261,7 @@
"name": "Duration (min)", "name": "Duration (min)",
"order": 2, "order": 2,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1327,8 +1326,7 @@
"name": "Years of experience", "name": "Years of experience",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1992,8 +1990,7 @@
"name": "Room capacity", "name": "Room capacity",
"order": 3, "order": 3,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
} }
], ],

View file

@ -78,7 +78,6 @@
"name": "Total cost", "name": "Total cost",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -486,8 +485,7 @@
"name": "Avg duration (min)", "name": "Avg duration (min)",
"order": 1, "order": 1,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -523,7 +521,6 @@
"name": "Avg cost", "name": "Avg cost",
"order": 3, "order": 3,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -1813,7 +1810,6 @@
"name": "Cost", "name": "Cost",
"order": 2, "order": 2,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },

View file

@ -63,8 +63,7 @@
"name": "Zip Code", "name": "Zip Code",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -742,8 +741,7 @@
"name": "Floor", "name": "Floor",
"order": 2, "order": 2,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -102,7 +102,6 @@
"name": "Cost", "name": "Cost",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },

View file

@ -1503,8 +1503,7 @@
"name":"Value (1-10)", "name":"Value (1-10)",
"order":5, "order":5,
"primary":false, "primary":false,
"number_type":"INTEGER", "number_decimal_places": 0,
"number_decimal_places":1,
"number_negative":false "number_negative":false
} }
], ],

View file

@ -174,8 +174,7 @@
"name": "SSN/TIN", "name": "SSN/TIN",
"order": 24, "order": 24,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -4484,8 +4483,7 @@
"name": "Avg per Week", "name": "Avg per Week",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -47,7 +47,6 @@
"name":"Price", "name":"Price",
"order":2, "order":2,
"primary":false, "primary":false,
"number_type":"DECIMAL",
"number_decimal_places":2, "number_decimal_places":2,
"number_negative":false "number_negative":false
}, },

View file

@ -131,8 +131,7 @@
"name": "Quantity", "name": "Quantity",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -188,8 +187,7 @@
"name": "Price", "name": "Price",
"order": 9, "order": 9,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1056,8 +1054,7 @@
"name": "Age", "name": "Age",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1464,8 +1461,7 @@
"name": "Coverage", "name": "Coverage",
"order": 8, "order": 8,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
} }
], ],

View file

@ -69,8 +69,7 @@
"name": "Asking price", "name": "Asking price",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -79,8 +78,7 @@
"name": "# of Bedrooms", "name": "# of Bedrooms",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -89,7 +87,6 @@
"name": "# of Bathrooms", "name": "# of Bathrooms",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
@ -161,8 +158,7 @@
"name": "Size", "name": "Size",
"order": 14, "order": 14,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -171,7 +167,6 @@
"name": "HOA fee", "name": "HOA fee",
"order": 15, "order": 15,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -195,7 +190,6 @@
"name": "Interest (%)", "name": "Interest (%)",
"order": 17, "order": 17,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -205,7 +199,6 @@
"name": "Property taxes", "name": "Property taxes",
"order": 18, "order": 18,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -215,7 +208,6 @@
"name": "Insurance", "name": "Insurance",
"order": 19, "order": 19,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -2862,8 +2854,7 @@
"name": "Noise level (1-10)", "name": "Noise level (1-10)",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -2924,7 +2915,6 @@
"name": "Public transport (km)", "name": "Public transport (km)",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
@ -2934,7 +2924,6 @@
"name": "Highway (km)", "name": "Highway (km)",
"order": 9, "order": 9,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },

View file

@ -124,8 +124,7 @@
"name": "Salary", "name": "Salary",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -692,7 +692,6 @@
"name": "Contract Value", "name": "Contract Value",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },

View file

@ -49,8 +49,7 @@
"name": "Resting HR", "name": "Resting HR",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -99,8 +98,7 @@
"name": "Weight (kg)", "name": "Weight (kg)",
"order": 8, "order": 8,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -109,7 +107,6 @@
"name": "Hours of Sleep", "name": "Hours of Sleep",
"order": 9, "order": 9,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
@ -1204,8 +1201,7 @@
"name": "Calories", "name": "Calories",
"order": 2, "order": 2,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1777,8 +1773,7 @@
"name": "Difficulty (1-10)", "name": "Difficulty (1-10)",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -94,8 +94,7 @@
"name": "Lifetime", "name": "Lifetime",
"order": 8, "order": 8,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -120,8 +119,7 @@
"name": "Zip Code", "name": "Zip Code",
"order": 11, "order": 11,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1016,8 +1014,7 @@
"name": "Amount", "name": "Amount",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -622,7 +622,6 @@
"name": "Est. Days", "name": "Est. Days",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },

View file

@ -106,8 +106,7 @@
"name": "Cook Time (min)", "name": "Cook Time (min)",
"order": 9, "order": 9,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -116,8 +115,7 @@
"name": "Prep Time (min)", "name": "Prep Time (min)",
"order": 10, "order": 10,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {

View file

@ -107,7 +107,6 @@
"name": "Hourly rate", "name": "Hourly rate",
"order": 9, "order": 9,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -1780,7 +1779,6 @@
"name": "In stock", "name": "In stock",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
@ -1790,7 +1788,6 @@
"name": "Ideal quantity", "name": "Ideal quantity",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
@ -2702,7 +2699,6 @@
"name": "Cost to make", "name": "Cost to make",
"order": 3, "order": 3,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -3443,7 +3439,6 @@
"name": "Price", "name": "Price",
"order": 2, "order": 2,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -4015,7 +4010,6 @@
"name": "Shift duration", "name": "Shift duration",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 1, "number_decimal_places": 1,
"number_negative": false "number_negative": false
} }

View file

@ -461,7 +461,6 @@
"name": "Duration", "name": "Duration",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -503,7 +502,6 @@
"name": "Cost", "name": "Cost",
"order": 13, "order": 13,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -1388,7 +1386,6 @@
"name": "Cost", "name": "Cost",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -1927,7 +1924,6 @@
"name": "Cost", "name": "Cost",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -3130,7 +3126,6 @@
"name": "Cost", "name": "Cost",
"order": 5, "order": 5,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -3731,7 +3726,6 @@
"name": "Cost", "name": "Cost",
"order": 2, "order": 2,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
@ -3741,7 +3735,6 @@
"name": "Budget", "name": "Budget",
"order": 3, "order": 3,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },

View file

@ -998,8 +998,7 @@
"name": "Est time (min)", "name": "Est time (min)",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -1829,7 +1828,6 @@
"name": "Price", "name": "Price",
"order": 8, "order": 8,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
} }
@ -2338,8 +2336,7 @@
"name": "Time to read (min)", "name": "Time to read (min)",
"order": 4, "order": 4,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
} }
], ],
@ -2656,7 +2653,6 @@
"name": "Admission", "name": "Admission",
"order": 3, "order": 3,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },

View file

@ -72,8 +72,7 @@
"name": "Capacity", "name": "Capacity",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": false "number_negative": false
}, },
{ {
@ -82,8 +81,7 @@
"name": "Rental Cost", "name": "Rental Cost",
"order": 7, "order": 7,
"primary": false, "primary": false,
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 2,
"number_negative": false "number_negative": false
}, },
{ {
@ -1328,7 +1326,6 @@
"name": "Cost", "name": "Cost",
"order": 6, "order": 6,
"primary": false, "primary": false,
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": false "number_negative": false
} }

View file

@ -51,7 +51,6 @@ def test_list_fields(api_client, data_fixture):
assert response_json[1]["id"] == field_3.id assert response_json[1]["id"] == field_3.id
assert response_json[1]["type"] == "number" assert response_json[1]["type"] == "number"
assert not response_json[1]["primary"] assert not response_json[1]["primary"]
assert response_json[1]["number_type"] == field_3.number_type
assert response_json[1]["number_decimal_places"] == field_3.number_decimal_places assert response_json[1]["number_decimal_places"] == field_3.number_decimal_places
assert response_json[1]["number_negative"] == field_3.number_negative assert response_json[1]["number_negative"] == field_3.number_negative
@ -390,15 +389,13 @@ def test_update_field(api_client, data_fixture):
assert response.status_code == HTTP_200_OK assert response.status_code == HTTP_200_OK
assert response_json["name"] == "Test 1" assert response_json["name"] == "Test 1"
assert response_json["type"] == "number" assert response_json["type"] == "number"
assert response_json["number_type"] == "INTEGER" assert response_json["number_decimal_places"] == 0
assert response_json["number_decimal_places"] == 1
assert response_json["number_negative"] assert response_json["number_negative"]
url = reverse("api:database:fields:item", kwargs={"field_id": text.id}) url = reverse("api:database:fields:item", kwargs={"field_id": text.id})
response = api_client.patch( response = api_client.patch(
url, url,
{ {
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
"number_negative": False, "number_negative": False,
}, },
@ -409,7 +406,6 @@ def test_update_field(api_client, data_fixture):
assert response.status_code == HTTP_200_OK assert response.status_code == HTTP_200_OK
assert response_json["name"] == "Test 1" assert response_json["name"] == "Test 1"
assert response_json["type"] == "number" assert response_json["type"] == "number"
assert response_json["number_type"] == "DECIMAL"
assert response_json["number_decimal_places"] == 2 assert response_json["number_decimal_places"] == 2
assert not response_json["number_negative"] assert not response_json["number_negative"]
@ -424,7 +420,6 @@ def test_update_field(api_client, data_fixture):
assert response.status_code == HTTP_200_OK assert response.status_code == HTTP_200_OK
assert response_json["name"] == "Test 2" assert response_json["name"] == "Test 2"
assert response_json["type"] == "boolean" assert response_json["type"] == "boolean"
assert "number_type" not in response_json
assert "number_decimal_places" not in response_json assert "number_decimal_places" not in response_json
assert "number_negative" not in response_json assert "number_negative" not in response_json
@ -457,6 +452,31 @@ def test_update_field(api_client, data_fixture):
assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION" assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION"
@pytest.mark.django_db
def test_update_field_number_type_deprecation_error(api_client, data_fixture):
user, token = data_fixture.create_user_and_token()
table = data_fixture.create_database_table(user=user)
number_field = data_fixture.create_number_field(
table=table, number_decimal_places=1
)
url = reverse("api:database:fields:item", kwargs={"field_id": number_field.id})
response = api_client.patch(
url,
{"number_type": "INTEGER"},
format="json",
HTTP_AUTHORIZATION=f"JWT {token}",
)
assert response.status_code == HTTP_400_BAD_REQUEST
assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION"
assert response.json()["detail"]["number_type"][0]["error"] == (
"The number_type option has been removed and can no longer be provided. "
"Instead set number_decimal_places to 0 for an integer or 1-5 for a "
"decimal."
)
@pytest.mark.django_db @pytest.mark.django_db
def test_delete_field(api_client, data_fixture): def test_delete_field(api_client, data_fixture):
user, token = data_fixture.create_user_and_token() user, token = data_fixture.create_user_and_token()

View file

@ -633,7 +633,7 @@ def test_number_field_type(api_client, data_fixture):
{ {
"name": "PositiveInt", "name": "PositiveInt",
"type": "number", "type": "number",
"number_type": "INTEGER", "number_decimal_places": 0,
"number_negative": False, "number_negative": False,
}, },
format="json", format="json",
@ -653,7 +653,7 @@ def test_number_field_type(api_client, data_fixture):
{ {
"name": "NegativeInt", "name": "NegativeInt",
"type": "number", "type": "number",
"number_type": "INTEGER", "number_decimal_places": 0,
"number_negative": True, "number_negative": True,
}, },
format="json", format="json",
@ -673,7 +673,6 @@ def test_number_field_type(api_client, data_fixture):
{ {
"name": "PositiveDecimal", "name": "PositiveDecimal",
"type": "number", "type": "number",
"number_type": "DECIMAL",
"number_negative": False, "number_negative": False,
"number_decimal_places": 2, "number_decimal_places": 2,
}, },
@ -694,7 +693,6 @@ def test_number_field_type(api_client, data_fixture):
{ {
"name": "NegativeDecimal", "name": "NegativeDecimal",
"type": "number", "type": "number",
"number_type": "DECIMAL",
"number_negative": True, "number_negative": True,
"number_decimal_places": 2, "number_decimal_places": 2,
}, },

View file

@ -19,7 +19,7 @@ def test_altering_value_of_referenced_field(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -702,7 +702,6 @@ def test_altering_type_of_underlying_causes_type_update(api_client, data_fixture
{ {
"name": "text", "name": "text",
"type": "number", "type": "number",
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
}, },
format="json", format="json",
@ -897,7 +896,7 @@ def test_can_type_an_invalid_formula_field(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -935,7 +934,7 @@ def test_can_type_a_valid_formula_field(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -981,7 +980,7 @@ def test_type_endpoint_returns_error_for_bad_syntax(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -1018,7 +1017,7 @@ def test_type_endpoint_returns_error_for_missing_parameters(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -1055,7 +1054,7 @@ def test_type_endpoint_returns_error_for_missing_field(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -1080,7 +1079,7 @@ def test_type_endpoint_returns_error_for_non_formula_field(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -1164,7 +1163,7 @@ def test_type_endpoint_returns_error_if_not_permissioned_for_field(
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
response = api_client.post( response = api_client.post(
reverse("api:database:fields:list", kwargs={"table_id": table.id}), reverse("api:database:fields:list", kwargs={"table_id": table.id}),
{"name": "number", "type": "number", "number_type": "INTEGER"}, {"name": "number", "type": "number", "number_decimal_places": 0},
format="json", format="json",
HTTP_AUTHORIZATION=f"JWT {token}", HTTP_AUTHORIZATION=f"JWT {token}",
) )
@ -1249,7 +1248,6 @@ def test_altering_type_of_underlying_causes_type_update_nested(
{ {
"name": "text", "name": "text",
"type": "number", "type": "number",
"number_type": "DECIMAL",
"number_decimal_places": 2, "number_decimal_places": 2,
}, },
format="json", format="json",

View file

@ -25,7 +25,6 @@ def test_get_table_serializer(data_fixture):
table=table, table=table,
order=4, order=4,
name="Price", name="Price",
number_type="DECIMAL",
number_negative=True, number_negative=True,
number_decimal_places=2, number_decimal_places=2,
) )
@ -148,7 +147,6 @@ def test_get_table_serializer(data_fixture):
table=table, table=table,
order=0, order=0,
name="Sale price", name="Sale price",
number_type="DECIMAL",
number_decimal_places=3, number_decimal_places=3,
number_negative=True, number_negative=True,
) )

View file

@ -11,7 +11,6 @@ from rest_framework.status import (
from baserow.contrib.database.fields.handler import FieldHandler from baserow.contrib.database.fields.handler import FieldHandler
from baserow.contrib.database.fields.registries import field_type_registry from baserow.contrib.database.fields.registries import field_type_registry
from baserow.contrib.database.fields.models import NUMBER_TYPE_DECIMAL
from baserow.contrib.database.rows.handler import RowHandler from baserow.contrib.database.rows.handler import RowHandler
from baserow.contrib.database.table.cache import ( from baserow.contrib.database.table.cache import (
invalidate_table_model_cache_and_related_models, invalidate_table_model_cache_and_related_models,
@ -653,7 +652,7 @@ def test_create_row_with_blank_decimal_field(api_client, data_fixture):
user, jwt_token = data_fixture.create_user_and_token() user, jwt_token = data_fixture.create_user_and_token()
table = data_fixture.create_database_table(user=user) table = data_fixture.create_database_table(user=user)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, order=1, name="TestDecimal", number_type=NUMBER_TYPE_DECIMAL table=table, order=1, name="TestDecimal", number_decimal_places=1
) )
response = api_client.post( response = api_client.post(
@ -981,7 +980,6 @@ def test_update_row(api_client, data_fixture):
table=table_3, table=table_3,
order=0, order=0,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
) )
model_3 = table_3.get_model() model_3 = table_3.get_model()

View file

@ -280,8 +280,7 @@ def test_meta_submit_form_view(api_client, data_fixture):
"field": { "field": {
"id": number_field.id, "id": number_field.id,
"type": "number", "type": "number",
"number_type": "INTEGER", "number_decimal_places": 0,
"number_decimal_places": 1,
"number_negative": False, "number_negative": False,
}, },
} }

View file

@ -710,7 +710,6 @@ def setup_testing_table(data_fixture):
price_field = data_fixture.create_number_field( price_field = data_fixture.create_number_field(
table=table, table=table,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=True, number_negative=True,
order=4, order=4,

View file

@ -207,17 +207,7 @@ def test_create_field(send_mock, data_fixture):
user=user, user=user,
table=table, table=table,
type_name="number", type_name="number",
name="Test number field", name="Test decimal with oversized decimal places value",
number_type="NOT_EXISTING",
)
with pytest.raises(ValueError):
handler.create_field(
user=user,
table=table,
type_name="number",
name="Test number field",
number_type="DECIMAL",
number_decimal_places=9999, number_decimal_places=9999,
) )
@ -226,8 +216,7 @@ def test_create_field(send_mock, data_fixture):
table=table, table=table,
type_name="number", type_name="number",
name="Test number field", name="Test number field",
number_type="INTEGER", number_decimal_places=0,
number_decimal_places=2,
number_negative=True, number_negative=True,
) )
@ -235,8 +224,7 @@ def test_create_field(send_mock, data_fixture):
assert number_field.name == "Test number field" assert number_field.name == "Test number field"
assert number_field.order == 2 assert number_field.order == 2
assert number_field.table == table assert number_field.table == table
assert number_field.number_type == "INTEGER" assert number_field.number_decimal_places == 0
assert number_field.number_decimal_places == 2
assert number_field.number_negative assert number_field.number_negative
handler.create_field( handler.create_field(
@ -395,12 +383,12 @@ def test_update_field(send_mock, data_fixture):
field=field, field=field,
new_type_name="number", new_type_name="number",
name="Number field", name="Number field",
number_type="INTEGER", number_decimal_places=0,
number_negative=False, number_negative=False,
) )
assert field.name == "Number field" assert field.name == "Number field"
assert field.number_type == "INTEGER" assert field.number_decimal_places == 0
assert field.number_negative is False assert field.number_negative is False
assert not hasattr(field, "text_default") assert not hasattr(field, "text_default")
@ -416,13 +404,11 @@ def test_update_field(send_mock, data_fixture):
field=field, field=field,
new_type_name="number", new_type_name="number",
name="Price field", name="Price field",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=True, number_negative=True,
) )
assert field.name == "Price field" assert field.name == "Price field"
assert field.number_type == "DECIMAL"
assert field.number_decimal_places == 2 assert field.number_decimal_places == 2
assert field.number_negative is True assert field.number_negative is True
@ -439,7 +425,6 @@ def test_update_field(send_mock, data_fixture):
field.refresh_from_db() field.refresh_from_db()
assert field.name == "Active" assert field.name == "Active"
assert not hasattr(field, "number_type")
assert not hasattr(field, "number_decimal_places") assert not hasattr(field, "number_decimal_places")
assert not hasattr(field, "number_negative") assert not hasattr(field, "number_negative")
@ -1077,7 +1062,7 @@ def test_can_convert_formula_to_numeric_field(data_fixture):
field=existing_formula_field, field=existing_formula_field,
new_type_name="number", new_type_name="number",
name="Price field", name="Price field",
number_type="INTEGER", number_decimal_places=0,
number_negative=True, number_negative=True,
) )

View file

@ -5,7 +5,7 @@ from decimal import Decimal
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from baserow.contrib.database.fields.handler import FieldHandler from baserow.contrib.database.fields.handler import FieldHandler
from baserow.contrib.database.fields.models import NumberField, NUMBER_TYPE_DECIMAL from baserow.contrib.database.fields.models import NumberField
from baserow.contrib.database.fields.registries import field_type_registry from baserow.contrib.database.fields.registries import field_type_registry
@ -29,7 +29,7 @@ from baserow.contrib.database.fields.registries import field_type_registry
None, None,
None, None,
], ],
{"number_type": "INTEGER", "number_negative": False}, {"number_decimal_places": 0, "number_negative": False},
), ),
( (
[ [
@ -47,7 +47,7 @@ from baserow.contrib.database.fields.registries import field_type_registry
None, None,
None, None,
], ],
{"number_type": "INTEGER", "number_negative": True}, {"number_decimal_places": 0, "number_negative": True},
), ),
( (
[ [
@ -66,7 +66,6 @@ from baserow.contrib.database.fields.registries import field_type_registry
None, None,
], ],
{ {
"number_type": "DECIMAL",
"number_negative": False, "number_negative": False,
"number_decimal_places": 1, "number_decimal_places": 1,
}, },
@ -88,7 +87,6 @@ from baserow.contrib.database.fields.registries import field_type_registry
None, None,
], ],
{ {
"number_type": "DECIMAL",
"number_negative": True, "number_negative": True,
"number_decimal_places": 3, "number_decimal_places": 3,
}, },
@ -139,7 +137,6 @@ def test_alter_number_field_column_type_negative(data_fixture):
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, table=table,
order=2, order=2,
number_type="DECIMAL",
number_negative=True, number_negative=True,
number_decimal_places=2, number_decimal_places=2,
) )
@ -170,7 +167,6 @@ def test_alter_number_field_column_type_negative(data_fixture):
def test_import_export_number_field(data_fixture): def test_import_export_number_field(data_fixture):
number_field = data_fixture.create_number_field( number_field = data_fixture.create_number_field(
name="Number field", name="Number field",
number_type="DECIMAL",
number_negative=True, number_negative=True,
number_decimal_places=2, number_decimal_places=2,
) )
@ -179,7 +175,6 @@ def test_import_export_number_field(data_fixture):
number_field_imported = number_field_type.import_serialized( number_field_imported = number_field_type.import_serialized(
number_field.table, number_serialized, {} number_field.table, number_serialized, {}
) )
assert number_field.number_type == number_field_imported.number_type
assert number_field.number_negative == number_field_imported.number_negative assert number_field.number_negative == number_field_imported.number_negative
assert number_field.number_decimal_places == ( assert number_field.number_decimal_places == (
number_field_imported.number_decimal_places number_field_imported.number_decimal_places
@ -192,7 +187,6 @@ def test_content_type_still_set_when_save_overridden(data_fixture):
field = NumberField( field = NumberField(
number_negative=False, number_negative=False,
number_decimal_places=1, number_decimal_places=1,
number_type=NUMBER_TYPE_DECIMAL,
order=1, order=1,
table=table, table=table,
) )

View file

@ -137,14 +137,14 @@ def test_rating_field_modification(data_fixture):
integer_field = data_fixture.create_number_field( integer_field = data_fixture.create_number_field(
table=table, table=table,
name="integer", name="integer",
number_type="INTEGER", number_decimal_places=0,
number_negative=True, number_negative=True,
) )
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, table=table,
name="decimal", name="decimal",
number_type="DECIMAL", number_decimal_places=1,
number_negative=True, number_negative=True,
) )
@ -267,14 +267,13 @@ def test_rating_field_modification(data_fixture):
user=user, user=user,
field=integer_field, field=integer_field,
new_type_name="number", new_type_name="number",
number_type="INTEGER", number_decimal_places=0,
number_negative=True, number_negative=True,
) )
field_handler.update_field( field_handler.update_field(
user=user, user=user,
field=decimal_field, field=decimal_field,
new_type_name="number", new_type_name="number",
number_type="DECIMAL",
number_negative=True, number_negative=True,
number_decimal_places=2, number_decimal_places=2,
) )

View file

@ -121,7 +121,6 @@ def test_create_row(send_mock, data_fixture):
price_field = data_fixture.create_number_field( price_field = data_fixture.create_number_field(
table=table, table=table,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=False, number_negative=False,
) )
@ -258,7 +257,6 @@ def test_get_row(data_fixture):
price_field = data_fixture.create_number_field( price_field = data_fixture.create_number_field(
table=table, table=table,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=False, number_negative=False,
) )
@ -303,7 +301,6 @@ def test_update_row(send_mock, data_fixture):
price_field = data_fixture.create_number_field( price_field = data_fixture.create_number_field(
table=table, table=table,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=False, number_negative=False,
) )
@ -465,7 +462,6 @@ def test_restore_row(send_mock, data_fixture):
price_field = data_fixture.create_number_field( price_field = data_fixture.create_number_field(
table=table, table=table,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=False, number_negative=False,
) )
@ -565,7 +561,6 @@ def test_has_row(data_fixture):
price_field = data_fixture.create_number_field( price_field = data_fixture.create_number_field(
table=table, table=table,
name="Price", name="Price",
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=False, number_negative=False,
) )

View file

@ -75,7 +75,6 @@ def test_get_table_model(data_fixture):
table=table_2, table=table_2,
order=0, order=0,
name="Sale price", name="Sale price",
number_type="DECIMAL",
number_decimal_places=3, number_decimal_places=3,
number_negative=True, number_negative=True,
) )

View file

@ -68,7 +68,7 @@ def test_equal_filter_type(data_fixture):
long_text_field = data_fixture.create_long_text_field(table=table) long_text_field = data_fixture.create_long_text_field(table=table)
integer_field = data_fixture.create_number_field(table=table) integer_field = data_fixture.create_number_field(table=table)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, number_type="DECIMAL", number_decimal_places=2 table=table, number_decimal_places=2
) )
boolean_field = data_fixture.create_boolean_field(table=table) boolean_field = data_fixture.create_boolean_field(table=table)
formula_field = data_fixture.create_formula_field(table=table, formula="'test'") formula_field = data_fixture.create_formula_field(table=table, formula="'test'")
@ -204,7 +204,7 @@ def test_not_equal_filter_type(data_fixture):
long_text_field = data_fixture.create_long_text_field(table=table) long_text_field = data_fixture.create_long_text_field(table=table)
integer_field = data_fixture.create_number_field(table=table) integer_field = data_fixture.create_number_field(table=table)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, number_type="DECIMAL", number_decimal_places=2 table=table, number_decimal_places=2
) )
boolean_field = data_fixture.create_boolean_field(table=table) boolean_field = data_fixture.create_boolean_field(table=table)
formula_field = data_fixture.create_formula_field(table=table, formula="'test'") formula_field = data_fixture.create_formula_field(table=table, formula="'test'")
@ -347,7 +347,6 @@ def test_contains_filter_type(data_fixture):
) )
number_field = data_fixture.create_number_field( number_field = data_fixture.create_number_field(
table=table, table=table,
number_type="DECIMAL",
number_negative=True, number_negative=True,
number_decimal_places=2, number_decimal_places=2,
) )
@ -567,7 +566,6 @@ def test_contains_not_filter_type(data_fixture):
) )
number_field = data_fixture.create_number_field( number_field = data_fixture.create_number_field(
table=table, table=table,
number_type="DECIMAL",
number_negative=True, number_negative=True,
number_decimal_places=2, number_decimal_places=2,
) )
@ -967,7 +965,6 @@ def test_higher_than_filter_type(data_fixture):
integer_field = data_fixture.create_number_field(table=table, number_negative=True) integer_field = data_fixture.create_number_field(table=table, number_negative=True)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, table=table,
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=True, number_negative=True,
) )
@ -1118,7 +1115,6 @@ def test_lower_than_filter_type(data_fixture):
integer_field = data_fixture.create_number_field(table=table, number_negative=True) integer_field = data_fixture.create_number_field(table=table, number_negative=True)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, table=table,
number_type="DECIMAL",
number_decimal_places=2, number_decimal_places=2,
number_negative=True, number_negative=True,
) )
@ -2214,7 +2210,7 @@ def test_empty_filter_type(data_fixture):
long_text_field = data_fixture.create_long_text_field(table=table) long_text_field = data_fixture.create_long_text_field(table=table)
integer_field = data_fixture.create_number_field(table=table) integer_field = data_fixture.create_number_field(table=table)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, number_type="DECIMAL", number_decimal_places=2 table=table, number_decimal_places=2
) )
date_field = data_fixture.create_date_field(table=table) date_field = data_fixture.create_date_field(table=table)
date_time_field = data_fixture.create_date_field( date_time_field = data_fixture.create_date_field(
@ -2369,7 +2365,7 @@ def test_not_empty_filter_type(data_fixture):
long_text_field = data_fixture.create_long_text_field(table=table) long_text_field = data_fixture.create_long_text_field(table=table)
integer_field = data_fixture.create_number_field(table=table) integer_field = data_fixture.create_number_field(table=table)
decimal_field = data_fixture.create_number_field( decimal_field = data_fixture.create_number_field(
table=table, number_type="DECIMAL", number_decimal_places=2 table=table, number_decimal_places=2
) )
date_field = data_fixture.create_date_field(table=table) date_field = data_fixture.create_date_field(table=table)
date_time_field = data_fixture.create_date_field( date_time_field = data_fixture.create_date_field(

View file

@ -16,6 +16,9 @@
tools, e.g. to various REST clients. tools, e.g. to various REST clients.
* Added search to gallery views. * Added search to gallery views.
* Views supporting search are properly updated when a column with a matching default value is added. * Views supporting search are properly updated when a column with a matching default value is added.
* **breaking change** Number field has been changed and doesn't use `number_type` property
anymore. The property `number_decimal_places` can be now set to `0` to indicate integers
instead.
## Released (2022-01-13 1.8.2) ## Released (2022-01-13 1.8.2)

View file

@ -1,87 +0,0 @@
<template>
<div>
<div class="control">
<label class="control__label control__label--small">{{
$t('fieldFormulaNumberSubForm.typeLabel')
}}</label>
<div class="control__elements">
<Dropdown
:class="{ 'dropdown--error': $v.numberType.$error }"
:value="numberType"
@input="changeNumberType($event)"
@hide="$v.numberType.$touch()"
>
<DropdownItem
:name="$t('fieldFormulaNumberSubForm.integer') + ' (1)'"
value="INTEGER"
></DropdownItem>
<DropdownItem
:name="$t('fieldFormulaNumberSubForm.decimal') + ' (1.0)'"
value="DECIMAL"
></DropdownItem>
</Dropdown>
</div>
</div>
<div v-show="numberType === 'DECIMAL'" class="control">
<label class="control__label control__label--small">{{
$t('fieldFormulaNumberSubForm.decimalPlacesLabel')
}}</label>
<div class="control__elements">
<Dropdown
v-model="values.number_decimal_places"
:class="{ 'dropdown--error': $v.values.number_decimal_places.$error }"
@hide="$v.values.number_decimal_places.$touch()"
>
<DropdownItem name="1.0" :value="1"></DropdownItem>
<DropdownItem name="1.00" :value="2"></DropdownItem>
<DropdownItem name="1.000" :value="3"></DropdownItem>
<DropdownItem name="1.0000" :value="4"></DropdownItem>
<DropdownItem name="1.00000" :value="5"></DropdownItem>
</Dropdown>
</div>
</div>
</div>
</template>
<script>
import { required } from 'vuelidate/lib/validators'
import form from '@baserow/modules/core/mixins/form'
import fieldSubForm from '@baserow/modules/database/mixins/fieldSubForm'
export default {
name: 'FieldNumberSubForm',
mixins: [form, fieldSubForm],
data() {
return {
allowedValues: ['number_decimal_places'],
values: {
number_decimal_places: 0,
},
}
},
computed: {
numberType() {
return this.values.number_decimal_places === 0 ? 'INTEGER' : 'DECIMAL'
},
},
methods: {
changeNumberType(newValue) {
if (newValue === 'INTEGER') {
this.values.number_decimal_places = 0
} else {
this.values.number_decimal_places = 1
}
},
},
validations: {
values: {
number_decimal_places: { required },
},
numberType: {
required,
},
},
}
</script>

View file

@ -1,27 +1,6 @@
<template> <template>
<div> <div>
<div class="control"> <div class="control">
<label class="control__label control__label--small">{{
$t('fieldNumberSubForm.typeLabel')
}}</label>
<div class="control__elements">
<Dropdown
v-model="values.number_type"
:class="{ 'dropdown--error': $v.values.number_type.$error }"
@hide="$v.values.number_type.$touch()"
>
<DropdownItem
:name="$t('fieldNumberSubForm.integer') + ' (1)'"
value="INTEGER"
></DropdownItem>
<DropdownItem
:name="$t('fieldNumberSubForm.decimal') + ' (1.0)'"
value="DECIMAL"
></DropdownItem>
</Dropdown>
</div>
</div>
<div v-show="values.number_type === 'DECIMAL'" class="control">
<label class="control__label control__label--small">{{ <label class="control__label control__label--small">{{
$t('fieldNumberSubForm.decimalPlacesLabel') $t('fieldNumberSubForm.decimalPlacesLabel')
}}</label> }}</label>
@ -31,15 +10,16 @@
:class="{ 'dropdown--error': $v.values.number_decimal_places.$error }" :class="{ 'dropdown--error': $v.values.number_decimal_places.$error }"
@hide="$v.values.number_decimal_places.$touch()" @hide="$v.values.number_decimal_places.$touch()"
> >
<DropdownItem name="1.0" :value="1"></DropdownItem> <DropdownItem name="0 (1)" :value="0"></DropdownItem>
<DropdownItem name="1.00" :value="2"></DropdownItem> <DropdownItem name="1 (1.0)" :value="1"></DropdownItem>
<DropdownItem name="1.000" :value="3"></DropdownItem> <DropdownItem name="2 (1.00)" :value="2"></DropdownItem>
<DropdownItem name="1.0000" :value="4"></DropdownItem> <DropdownItem name="3 (1.000)" :value="3"></DropdownItem>
<DropdownItem name="1.00000" :value="5"></DropdownItem> <DropdownItem name="4 (1.0000)" :value="4"></DropdownItem>
<DropdownItem name="5 (1.00000)" :value="5"></DropdownItem>
</Dropdown> </Dropdown>
</div> </div>
</div> </div>
<div class="control"> <div v-if="allowSetNumberNegative" class="control">
<div class="control__elements"> <div class="control__elements">
<Checkbox v-model="values.number_negative">{{ <Checkbox v-model="values.number_negative">{{
$t('fieldNumberSubForm.allowNegative') $t('fieldNumberSubForm.allowNegative')
@ -58,23 +38,29 @@ import fieldSubForm from '@baserow/modules/database/mixins/fieldSubForm'
export default { export default {
name: 'FieldNumberSubForm', name: 'FieldNumberSubForm',
mixins: [form, fieldSubForm], mixins: [form, fieldSubForm],
props: {
allowSetNumberNegative: {
type: Boolean,
required: false,
default: true,
},
},
data() { data() {
let allowedValues = ['number_decimal_places']
let values = { number_decimal_places: 0 }
if (this.allowSetNumberNegative) {
allowedValues = [...allowedValues, 'number_negative']
values = { ...values, number_negative: false }
}
return { return {
allowedValues: [ allowedValues,
'number_type', values,
'number_decimal_places',
'number_negative',
],
values: {
number_type: 'INTEGER',
number_decimal_places: 1,
number_negative: false,
},
} }
}, },
validations: { validations: {
values: { values: {
number_type: { required },
number_decimal_places: { required }, number_decimal_places: { required },
}, },
}, },

View file

@ -1,11 +1,12 @@
<template> <template>
<div> <div>
<FieldFormulaNumberSubForm <FieldNumberSubForm
v-if="formulaType === 'number'" v-if="formulaType === 'number'"
:default-values="defaultValues" :default-values="defaultValues"
:table="table" :table="table"
:allow-set-number-negative="false"
> >
</FieldFormulaNumberSubForm> </FieldNumberSubForm>
<FieldDateSubForm <FieldDateSubForm
v-else-if="['date', 'last_modified', 'created_on'].includes(formulaType)" v-else-if="['date', 'last_modified', 'created_on'].includes(formulaType)"
:default-values="defaultValues" :default-values="defaultValues"
@ -15,14 +16,14 @@
</div> </div>
</template> </template>
<script> <script>
import FieldFormulaNumberSubForm from '@baserow/modules/database/components/field/FieldFormulaNumberSubForm' import FieldNumberSubForm from '@baserow/modules/database/components/field/FieldNumberSubForm'
import FieldDateSubForm from '@baserow/modules/database/components/field/FieldDateSubForm' import FieldDateSubForm from '@baserow/modules/database/components/field/FieldDateSubForm'
import form from '@baserow/modules/core/mixins/form' import form from '@baserow/modules/core/mixins/form'
import fieldSubForm from '@baserow/modules/database/mixins/fieldSubForm' import fieldSubForm from '@baserow/modules/database/mixins/fieldSubForm'
export default { export default {
name: 'FormulaTypeSubForms', name: 'FormulaTypeSubForms',
components: { FieldFormulaNumberSubForm, FieldDateSubForm }, components: { FieldNumberSubForm, FieldDateSubForm },
mixins: [form, fieldSubForm], mixins: [form, fieldSubForm],
props: { props: {
table: { table: {

View file

@ -865,21 +865,19 @@ export class NumberFieldType extends FieldType {
if (value === '' || isNaN(value) || value === undefined || value === null) { if (value === '' || isNaN(value) || value === undefined || value === null) {
return null return null
} }
const decimalPlaces =
field.number_type === 'DECIMAL' ? field.number_decimal_places : 0
let number = new BigNumber(value) let number = new BigNumber(value)
if (!field.number_negative && number.isLessThan(0)) { if (!field.number_negative && number.isLessThan(0)) {
number = 0 number = 0
} }
return number.toFixed(decimalPlaces) return number.toFixed(field.number_decimal_places)
} }
getDocsDataType(field) { getDocsDataType(field) {
return field.number_type === 'DECIMAL' ? 'decimal' : 'number' return field.number_decimal_places > 0 ? 'decimal' : 'number'
} }
getDocsDescription(field) { getDocsDescription(field) {
let t = field.number_type === 'INTEGER' ? 'number' : 'decimal' let t = field.number_decimal_places === 0 ? 'number' : 'decimal'
if (!field.number_negative) { if (!field.number_negative) {
t += 'Positive' t += 'Positive'
} }
@ -889,7 +887,7 @@ export class NumberFieldType extends FieldType {
} }
getDocsRequestExample(field) { getDocsRequestExample(field) {
if (field.number_type === 'DECIMAL') { if (field.number_decimal_places > 0) {
let number = '0.' let number = '0.'
for (let i = 1; i <= field.number_decimal_places; i++) { for (let i = 1; i <= field.number_decimal_places; i++) {
number += '0' number += '0'

View file

@ -35,9 +35,8 @@ const mockedFields = {
primary: false, primary: false,
table_id: 42, table_id: 42,
type: 'number', type: 'number',
number_decimal_places: 1, number_decimal_places: 0,
number_negative: false, number_negative: false,
number_type: 'INTEGER',
}, },
rating: { rating: {
id: 16, id: 16,