Skip to content

Commit

Permalink
🔊 [#4927] System check for missing allow_blank on non-required charfi…
Browse files Browse the repository at this point in the history
…elds

because in most cases it is desired to allow empty strings as well
  • Loading branch information
stevenbal committed Jan 14, 2025
1 parent f16d700 commit e56665d
Showing 1 changed file with 60 additions and 0 deletions.
60 changes: 60 additions & 0 deletions src/openforms/utils/checks.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import inspect
import os
from pathlib import Path

from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.contrib.sessions.backends.cache import SessionStore
from django.core.checks import Error, Warning, register
from django.forms import ModelForm

from rest_framework.serializers import CharField, Serializer, empty
from rest_framework.test import APIRequestFactory
from treebeard.forms import MoveNodeForm


Expand Down Expand Up @@ -81,3 +87,57 @@ def check_missing_init_files(app_configs, **kwargs):
)

return errors


@register
def check_serializer_non_required_charfield_allow_blank_true( # pragma: no cover
app_configs, **kwargs
):
"""
Check for serializers.CharFields that have ``required=False``, but not ``allow_blank=True``
to avoid bogus validation errors occurring when empty strings are provided by the frontend.
"""
src_dir = Path(__file__).parent.parent.parent
modules = [str(x).split("/")[-1] for x in src_dir.iterdir() if x.is_dir()]
request = APIRequestFactory().get("/")
request.user = AnonymousUser()
request.session = SessionStore()

errors = []
serializers = get_subclasses(Serializer)
for serializer_class in serializers:
# We're only interested in classes defined in this codebase, not in classes
# defined in libraries
if serializer_class.__module__.split(".")[0] not in modules:
continue

if hasattr(serializer_class, "Meta") and not hasattr(
serializer_class.Meta, "model"
):
continue

serializer = serializer_class(context={"request": request})
fields = serializer.fields

for field_name, field in fields.items():
if not isinstance(field, CharField) or field.read_only:
continue

if (
not field.required
and field.default in ("", None, empty)
and not field.allow_blank
):
file_path = inspect.getfile(serializer_class)

errors.append(
Warning(
(
f"{serializer_class.__module__}.{serializer_class.__qualname__}.{field_name} does not have `allow_blank=True`\n"
f"{file_path}"
),
hint="Consider setting `allow_blank=True` to allow passing of empty strings",
id="utils.W002",
)
)
return errors

0 comments on commit e56665d

Please sign in to comment.