Skip to content

Commit

Permalink
Fix nested models still having default values in models that use `For…
Browse files Browse the repository at this point in the history
…UpdateMetaclass` (#15202)
  • Loading branch information
themylogin authored Dec 15, 2024
1 parent 33f5db0 commit f823fdf
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/middlewared/middlewared/api/base/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,16 @@ def __new__(mcls, name, bases, namespaces, **kwargs):
class _ForUpdateSerializerMixin(PydanticBaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, serializer):
return {k: v for k, v in serializer(self).items() if v != undefined}
aliases = {field.alias or name: name for name, field in self.model_fields.items()}

return {
k: v
for k, v in serializer(self).items()
if (
(getattr(self, aliases[k]) != undefined) if k in aliases and hasattr(self, aliases[k])
else v != undefined
)
}


def _field_for_update(field):
Expand Down
30 changes: 30 additions & 0 deletions src/middlewared/middlewared/pytest/unit/api/base/test_model.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from pydantic import Field
import pytest

from middlewared.api.base import (BaseModel, Excluded, excluded_field, ForUpdateMetaclass, single_argument_args,
single_argument_result)
from middlewared.api.base.handler.accept import accept_params
from middlewared.api.base.handler.result import serialize_result
from middlewared.api.v25_04_0.pool_snapshottask import PoolSnapshotTaskCron
from middlewared.service_exception import ValidationErrors


Expand Down Expand Up @@ -64,3 +66,31 @@ class MethodResult(BaseModel):
count: int

assert serialize_result(MethodResult, {"name": "ivan", "count": 1}, True) == {"name": "ivan", "count": 1}


def test_update_with_cron():
class CreateObjectWithCron(BaseModel):
schedule: PoolSnapshotTaskCron = Field(default_factory=PoolSnapshotTaskCron)

class UpdateObjectWithCron(CreateObjectWithCron, metaclass=ForUpdateMetaclass):
pass

class UpdateWithCronArgs(BaseModel):
id: int
data: UpdateObjectWithCron

assert accept_params(UpdateWithCronArgs, [1, {}]) == [1, {}]


def test_update_with_alias():
class CreateObjectWithAlias(BaseModel):
pass_: str = Field(alias="pass")

class UpdateObjectWithAlias(CreateObjectWithAlias, metaclass=ForUpdateMetaclass):
pass

class UpdateWithAliasArgs(BaseModel):
id: int
data: UpdateObjectWithAlias

assert accept_params(UpdateWithAliasArgs, [1, {"pass": "1"}]) == [1, {"pass": "1"}]

0 comments on commit f823fdf

Please sign in to comment.