Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support serializing with the by_alias arg set #10

Merged
merged 7 commits into from
Aug 3, 2023

Conversation

mortenkrane
Copy link
Member

Pydantic will, by default, serialize models with snake case. This change enables us to define custom aliases for the fields in the Pydantic model, and have the @api decorator serialize the model using those aliases.

This behavior was possible with the previous version of Pydantic, but was removed as part of the upgrade. Probably because Pydantic does things differently internally.

The usage we want is this:

  1. Define a custom base class, that defines field aliases.
class CamelModel(pydantic.BaseModel):
    model_config = pydantic.ConfigDict(
        alias_generator=camel_case,
        populate_by_name=True,
    )

camel_case here is a function that converts field names from snake case to camel case.

  1. Use this as the base for the Pydantic classes you want to serialize with camel case:
class Person(CamelModel):
   first_name: str
   last_name: str
  1. Create @api view that returns an instance of this class, and makes it serialize with the alias. (Or create a local decorator that wraps @api and hardcodes this argument):
@api(method="GET", serialize_by_alias=True)
def person((request: HttpRequest) -> Person:

    return Person(first_name="Monty", last_name="Python")

The result would be a payload that looks something like this:

{
    "firstName": "Monty",
    "lastName": "Python"
}

An alternative approach could be to move away from the TypeAdapter approach, and instead just call response.dump_model_json(). Then the custom base class could define an override to it that and do whatever it wants with it (using by_alias, for example, but potentially also other things).

@mortenkrane mortenkrane requested a review from ljodal August 3, 2023 09:06
@ljodal
Copy link
Contributor

ljodal commented Aug 3, 2023

An alternative approach could be to move away from the TypeAdapter approach, and instead just call response.dump_model_json(). Then the custom base class could define an override to it that and do whatever it wants with it (using by_alias, for example, but potentially also other things).

The type adapter is needed to support other things, like dataclasses and typed dicts, but we could add some logic to check if the view returns a pydantic model.

@mortenkrane
Copy link
Member Author

An alternative approach could be to move away from the TypeAdapter approach, and instead just call response.dump_model_json(). Then the custom base class could define an override to it that and do whatever it wants with it (using by_alias, for example, but potentially also other things).

The type adapter is needed to support other things, like dataclasses and typed dicts, but we could add some logic to check if the view returns a pydantic model.

OK, get it 👍 . Then I think the smallest possible change is what's in the PR now. If we at some point need to leverage more of the flexibility that dump_model_json would provide, we can consider changing it then.



class MyPydanticModel(BaseModel):
a: int
an_integer: int
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to this name to clearly illustrate the difference between snake case and camel case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ljodal I added a test case as well, if you want to have a look at it.

@mortenkrane mortenkrane merged commit 2a6846b into main Aug 3, 2023
9 checks passed
@mortenkrane mortenkrane deleted the mortenkrane/support-serializing-by-field-aliases branch August 3, 2023 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants