Pydantic/Django Ninja использует только существующие ключи (даже с None)
создание приложения на Django Ninja со схемами:
class NumericalFilterSchema(Schema):
gt: Optional[int] = None
lt: Optional[int] = None
gte: Optional[int] = None
lte: Optional[int] = None
exact: Optional[int] = None
class Config(Schema.Config):
extra = "forbid"
class StringFilterSchema(Schema):
contains: Optional[str] = None
icontains: Optional[str] = None
exact: Optional[str] = None
class Config(Schema.Config):
extra = "forbid"
class InputsSchema(Schema):
major_version: Optional[NumericalFilterSchema] = None
app_name: Optional[StringFilterSchema] = None
class Config(Schema.Config):
extra = "forbid"
class InputSchema(Schema):
filters: InputsSchema
class Config(Schema.Config):
extra = "forbid"
, который я затем использую в конечной точке следующим образом:
@router_v1.post(
"/apps",
tags=["..."],
auth=AuthBearer(),
)
def dynamic_filter(request: HttpRequest, filters: InputsSchema):
query = Q()
# import ipdb
# ipdb.set_trace()
for key, value in filters.dict(exclude_none=True).items():
# key = translate_field(key) # just abstraction between endpoint keys to db keys
if isinstance(value, dict):
for k, v in value.items():
if v is not None:
query &= Q(**{f"{key}__{k}": v})
else:
query &= Q(**{key: value})
results = Apps.objects.filter(query)
...
Проблема:
Как видно из построения запроса, я исключаю все значения None, что вполне нормально в большинстве случаев, например:
{
"major_version": {
"exact": 3
},
"app_name": {
"icontains": "google"
}
}
это вернет схему
InputsSchema(major_version=NumericalFilterSchema(gt=None, lt=None, gte=None, lte=None, exact=3), app_name=StringFilterSchema(contains=None, icontains='google', exact=None))
что замечательно... но что, если мое входное значение - None?
например:
{
"major_version": {
"exact": null
},
"app_name": {
"icontains": "google"
}
}
здесь пара ключ-значение exact
разрешится в "exact": None
, которая будет такой же, как и другие ключи после проверки pydantic/ninja:
InputsSchema(major_version=NumericalFilterSchema(gt=None, lt=None, gte=None, lte=None, exact=None), app_name=StringFilterSchema(contains=None, icontains='google', exact=None))
, что «отстой» для меня, потому что я использую exclude_none=True
, который отфильтровывает все Nones - даже то значение, которое я дал.
Есть ли способ избежать создания несуществующих ключей в созданной модели? Итак, после валидации запроса у меня будет что-то вроде:
InputsSchema(major_version=NumericalFilterSchema(exact=None), app_name=StringFilterSchema(icontains='google'))
так что мне не нужно использовать exclude_none=True
и передавать None
в запрос?
Спасибо!
Джанго __exact
lookup [Django-doc] действительно смотрит, является ли объект NULL
, и таким образом __exact=None
преобразует его в … IS NULL
условие.
Но вы также можете фильтровать с помощью __isnull
lookup [Django-doc], если вы установите его в __isnull=True
, то это преобразует его в … IS NULL
условие, а для __isnull=False
вы таким образом используете … IS NOT NULL
.
Таким образом, вы, вероятно, можете добавить isnull
в качестве условия фильтрации, которое, если True
/true
, заставит значение быть NULL
/None
.