Skip to content

Commit ed98578

Browse files
Fix rejecting null on optional fields (#761)
1 parent 0ee079b commit ed98578

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

aiohttp_admin/backends/abc.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import warnings
55
from abc import ABC, abstractmethod
6+
from collections.abc import Sequence
67
from datetime import date, datetime, time
78
from enum import Enum
89
from functools import cached_property, partial
@@ -16,6 +17,11 @@
1617
from ..security import check, permissions_as_dict
1718
from ..types import ComponentState, InputState
1819

20+
if sys.version_info >= (3, 10):
21+
from typing import TypeAlias
22+
else:
23+
from typing_extensions import TypeAlias
24+
1925
if sys.version_info >= (3, 12):
2026
from typing import TypedDict
2127
else:
@@ -110,7 +116,7 @@ def __init__(self) -> None:
110116
if "id" in self.fields and self.primary_key != "id":
111117
warnings.warn("A non-PK 'id' column is likely to break the admin.", stacklevel=2)
112118

113-
d = {k: INPUT_TYPES.get(v["type"], str) for k, v in self.inputs.items()}
119+
d = {k: self._get_input_type(v) for k, v in self.inputs.items()}
114120
# For runtime type checking only.
115121
self._record_type = TypedDict("RecordType", d, total=False) # type: ignore[misc]
116122

@@ -313,6 +319,12 @@ async def _delete_many(self, request: web.Request) -> web.Response:
313319
raise web.HTTPNotFound()
314320
return json_response({"data": ids})
315321

322+
def _get_input_type(self, inp: InputState) -> TypeAlias:
323+
t = INPUT_TYPES.get(inp["type"], str)
324+
validators = inp.get("props", {}).get("validate", ())
325+
assert isinstance(validators, Sequence) # noqa: S101
326+
return t if any(v["name"] == "required" for v in validators) else Optional[t]
327+
316328
@cached_property
317329
def routes(self) -> tuple[web.RouteDef, ...]:
318330
"""Routes to act on this resource.

tests/test_backends_abc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import json
2+
from collections.abc import Awaitable, Callable
3+
4+
from aiohttp.test_utils import TestClient
5+
6+
_Login = Callable[[TestClient], Awaitable[dict[str, str]]]
7+
8+
9+
async def test_create_with_null(admin_client: TestClient, login: _Login) -> None:
10+
h = await login(admin_client)
11+
assert admin_client.app
12+
url = admin_client.app["admin"].router["dummy2_create"].url_for()
13+
p = {"data": json.dumps({"msg": None})}
14+
async with admin_client.post(url, params=p, headers=h) as resp:
15+
assert resp.status == 200, await resp.text()
16+
assert await resp.json() == {"data": {"id": 4, "msg": None}}

0 commit comments

Comments
 (0)