Replies: 4 comments 2 replies
-
I see that you marked your payload as Django Ninja’s you either need to send your data as json payload (application/json) or get form data as key-value [str, str] and then for each value parse nested json value that's jus simply how html form works |
Beta Was this translation helpful? Give feedback.
-
@vitalik # checks
def set_user_conditions(conditions, user):
if not conditions:
for cond in ('diseases', 'allergies', 'surgeries'):
setattr(user, cond, [])
return 200
data = json.loads(conditions)
conditions = data.get('questions')
for condition in conditions:
answers = condition.get('answers', [])
cond = condition['question'].lower()
match cond:
case 'diseases':
setattr(user, cond, answers)
case 'allergies':
setattr(user, cond, answers)
case 'surgeries':
setattr(user, cond, answers)
case _:
return f'unsupported condition: {cond}'
return 200
# api
@router.patch('medical', auth=JWTAuth(), response=UPDATE_RESPONSE, tags=['user'])
def update_user_medical_info(
request,
payload: Form[schema.UserMedicalInSchema] = None,
):
user = request.user
if payload:
data = checks.normalize_medical_info(payload.dict())
check_result = checks.medial_info(data)
if check_result != 200:
return schema_gen.error_response(400, *check_result)
for field, value in data.items():
if field == 'conditions':
check_result = checks.set_user_conditions(value, user)
if check_result != 200:
return schema_gen.error_response(400, check_result)
continue
setattr(user, field, value)
user.save()
return 204, None
return schema_gen.error_response(400, 'no data provided') |
Beta Was this translation helpful? Give feedback.
-
@smjt2000 I think you can leverage pydantic type adapter here to validate what's coming in form fields - basically you input flat params as string and then use typeadapter to correctly validate them with pydantic: import json
from typing import Annotated
from pydantic import BeforeValidator, TypeAdapter
from ninja import NinjaAPI, Schema, Form
def string_json(value: str):
try:
return json.loads(value)
except:
raise ValueError("Not a valid JSON")
class AnswerSchema(Schema):
key: str
value: str
class UserDisease(Schema):
question: str
answers: list[AnswerSchema]
DiseaseAdapter = TypeAdapter(Annotated[UserDisease, BeforeValidator(string_json)])
api = NinjaAPI()
@api.post("/medical")
def medical(request, diseases: Form[str]):
try:
data = DiseaseAdapter.validate_python(diseases)
except ValueError as e:
return {"error": str(e)}
return data.dict() ![]() |
Beta Was this translation helpful? Give feedback.
-
I just want to do a bit of a "me too" to this discussion, because I came here looking for information on optional payloads using JSON. I have an API that's involved in booking events. Some events can be booked by anyone, others require an invitation. I have a booking endpoint that I want to optionally accept a payload so it handles both cases: booking with and without an invitation. Here's the payload schema: class BookEventSchemaIn(Schema):
invitation_id: int = Field(gt=0) and the endpoint definition: @event_router.post(
"/events/{event_id}/book/",
response={201: None, 400: ApiErrorSchema},
)
def book_event(
request: HttpRequest, event_id: int, payload: BookEventSchemaIn | None = None
) -> tuple[int, None]: Whether I do I've found switching the endpoint definition to a Form based payload works: def book_event(
request: HttpRequest, event_id: int, payload: BookEventSchemaIn = Form(...) The payload is no longer required, but the generated schema no longer shows the endpoint as allowing a JSON payload. Is there anyway to achieve the same behaviour, but using a JSON payload? |
Beta Was this translation helpful? Give feedback.
-
Here I have this code that I want to get from user with PATCH method.
the issue is I always got "missing" error for this type of fields.
And this is the error:
I sent the request from Ninja docs page(/api/docs) and always get this error for any field which is List input.
Also I get this error in my terminal(
manage.py runserver
) when change 'disease' in 'UserMedicalInSchema' todisease = Optional[UserDisease] = None
and this is the API.
Beta Was this translation helpful? Give feedback.
All reactions