-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Hi @mr-fatalyst, thank you for the amazing work on oxyde-admin!
I've been using it alongside FastAPI and Oxyde ORM, and I noticed a friction point regarding how the Vue frontend communicates with strict Pydantic v2 models.
The Problem:
Currently, when a user leaves an optional number (int | None, float | None) or date field blank in the admin creation/edit form, the frontend submits an empty string ("") in the JSON payload instead of null.
Because Oxyde uses strict Pydantic validation, Pydantic immediately rejects the "" for these data types, throwing a 422 Unprocessable Content error.
Right now, the only workaround is forcing developers to write boilerplate @model_validator(mode='before') hooks on every single model to manually scrub "" into None:
# Current annoying workaround required on user models
for key, value in list(data.items()):
if value == "":
data[key] = NoneThe Proposed Solution:
Since oxyde-admin already introspects the Pydantic schema to generate the UI, it should use that schema to safely scrub the payload before instantiation. This can be handled in the Python backend adapter to keep the frontend dumb and lightweight.
In oxyde_admin/api/routes.py (inside the create_record and update_record handlers), we can introduce a payload cleaner:
def sanitize_payload(model_class, payload: dict) -> dict:
"""
Checks the incoming payload against the Pydantic model fields.
If a field is expecting a numeric, date, or boolean type and receives "",
it converts it to None to satisfy strict validation.
"""
clean_data = payload.copy()
for field_name, field_info in model_class.model_fields.items():
if field_name in clean_data and clean_data[field_name] == "":
# If the field allows None, sanitize it.
# (Alternatively, check if the field annotation includes int, float, date, datetime)
if not field_info.is_required() or type(None) in field_info.annotation.__args__:
clean_data[field_name] = None
return clean_dataThen, just wrap the incoming data before passing it to the database:
clean_data = sanitize_payload(model, data)
record = await model.objects.create(**clean_data)Why this is a must-have:
It aligns perfectly with Oxyde’s philosophy of "zero boilerplate." Developers shouldn't have to write custom Pydantic pre-processors just to handle standard HTML form-clearing behavior.