Skip to content

Commit f6225db

Browse files
authored
Don't allow 0 as valid form value for required rating field (baserow#5084)
1 parent 05ffd44 commit f6225db

5 files changed

Lines changed: 125 additions & 10 deletions

File tree

backend/src/baserow/contrib/database/fields/field_types.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -910,16 +910,29 @@ def prepare_value_for_db(self, instance, value):
910910
return value
911911

912912
def get_serializer_field(self, instance, **kwargs):
913-
return serializers.IntegerField(
914-
**{
915-
"required": False,
916-
"allow_null": False,
917-
"min_value": 0,
918-
"default": 0,
919-
"max_value": instance.max_value,
920-
**kwargs,
921-
}
922-
)
913+
required = kwargs.get("required", False)
914+
field_kwargs = {
915+
"required": False,
916+
"allow_null": False,
917+
"min_value": 0,
918+
"default": 0,
919+
"max_value": instance.max_value,
920+
**kwargs,
921+
}
922+
if required:
923+
field_kwargs.pop("default", None)
924+
validators = field_kwargs.get("validators", [])
925+
validators.append(self._rating_required_validator)
926+
field_kwargs["validators"] = validators
927+
return serializers.IntegerField(**field_kwargs)
928+
929+
@staticmethod
930+
def _rating_required_validator(value):
931+
if value == 0:
932+
raise ValidationError(
933+
"This field is required.",
934+
code="required",
935+
)
923936

924937
def force_same_type_alter_column(self, from_field, to_field):
925938
"""

backend/tests/baserow/contrib/database/api/views/form/test_form_view_views.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2995,6 +2995,89 @@ def test_submit_form_view_for_required_number_field_with_0(api_client, data_fixt
29952995
}
29962996

29972997

2998+
@pytest.mark.django_db
2999+
def test_submit_form_view_for_required_rating_field_with_0(api_client, data_fixture):
3000+
user, token = data_fixture.create_user_and_token()
3001+
table = data_fixture.create_database_table(user=user)
3002+
form = data_fixture.create_form_view(
3003+
table=table,
3004+
submit_action_message="Test",
3005+
submit_action_redirect_url="https://baserow.io",
3006+
)
3007+
rating_field = data_fixture.create_rating_field(table=table)
3008+
data_fixture.create_form_view_field_option(
3009+
form, rating_field, required=True, enabled=True, order=2
3010+
)
3011+
3012+
url = reverse("api:database:views:form:submit", kwargs={"slug": form.slug})
3013+
3014+
# Submitting 0 should fail because 0 means "no rating" for a required rating field
3015+
response = api_client.post(
3016+
url,
3017+
{f"field_{rating_field.id}": 0},
3018+
format="json",
3019+
HTTP_AUTHORIZATION=f"JWT {token}",
3020+
)
3021+
assert response.status_code == HTTP_400_BAD_REQUEST
3022+
response_json = response.json()
3023+
assert response_json["detail"][f"field_{rating_field.id}"][0]["code"] == "required"
3024+
3025+
# Submitting a valid rating should succeed
3026+
response = api_client.post(
3027+
url,
3028+
{f"field_{rating_field.id}": 3},
3029+
format="json",
3030+
HTTP_AUTHORIZATION=f"JWT {token}",
3031+
)
3032+
assert response.status_code == HTTP_200_OK
3033+
response_json = response.json()
3034+
assert response_json == {
3035+
"row_id": AnyInt(),
3036+
"submit_action": "MESSAGE",
3037+
"submit_action_message": "Test",
3038+
"submit_action_redirect_url": "https://baserow.io",
3039+
}
3040+
3041+
3042+
@pytest.mark.django_db
3043+
def test_submit_form_view_for_non_required_rating_field_with_0(
3044+
api_client, data_fixture
3045+
):
3046+
"""
3047+
Submitting 0 should succeed when the rating field is not required.
3048+
"""
3049+
3050+
user, token = data_fixture.create_user_and_token()
3051+
table = data_fixture.create_database_table(user=user)
3052+
form = data_fixture.create_form_view(
3053+
table=table,
3054+
submit_action_message="Test",
3055+
submit_action_redirect_url="https://baserow.io",
3056+
)
3057+
rating_field = data_fixture.create_rating_field(table=table)
3058+
data_fixture.create_form_view_field_option(
3059+
form, rating_field, required=False, enabled=True, order=2
3060+
)
3061+
3062+
url = reverse("api:database:views:form:submit", kwargs={"slug": form.slug})
3063+
3064+
response = api_client.post(
3065+
url,
3066+
{f"field_{rating_field.id}": 0},
3067+
format="json",
3068+
HTTP_AUTHORIZATION=f"JWT {token}",
3069+
)
3070+
3071+
assert response.status_code == HTTP_200_OK
3072+
response_json = response.json()
3073+
assert response_json == {
3074+
"row_id": AnyInt(),
3075+
"submit_action": "MESSAGE",
3076+
"submit_action_message": "Test",
3077+
"submit_action_redirect_url": "https://baserow.io",
3078+
}
3079+
3080+
29983081
@pytest.mark.django_db
29993082
def test_upload_file_view(api_client, data_fixture, tmpdir):
30003083
user, token = data_fixture.create_user_and_token(
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "bug",
3+
"message": "Rating field now doesn't accept 0 as a valid value in form views when the field is required",
4+
"issue_origin": "github",
5+
"issue_number": 4985,
6+
"domain": "database",
7+
"bullet_points": [],
8+
"created_at": "2026-03-30"
9+
}

web-frontend/modules/database/components/row/RowEditFieldRating.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
@update="update"
1111
/>
1212
</div>
13+
<div v-show="touched && !isValid()" class="error">
14+
{{ getError() }}
15+
</div>
1316
</div>
1417
</template>
1518

web-frontend/modules/database/fieldTypes.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,13 @@ export class RatingFieldType extends FieldType {
19941994
return 0
19951995
}
19961996

1997+
isEmpty(field, value) {
1998+
if (value === 0) {
1999+
return true
2000+
}
2001+
return super.isEmpty(field, value)
2002+
}
2003+
19972004
canUpsert() {
19982005
return true
19992006
}

0 commit comments

Comments
 (0)