How make dataclass for partial update(Patch method)?

767 Views Asked by At

Use @dataclass in my project. Now I want to implement @dataclass for PATCH method(partial_update) and initialize only provided arguments.

For example:

@dataclass
class Person:
    id: int
    first_name: Optional[str]
    last_name: Optional[str]
    birthday: Optional[datetime.date]

and use it like:

person = Person(id=1, first_name ='Andrew')

so now person have only two arguments id and first_name(person.id, person.first_name )

Does someone have understanding how to implement such stuff? maybe is some wrapper for @dataclass?

P.S. Can't use

@dataclass
class Person:
    id: int
    first_name: Optional[str] = None
    last_name: Optional[str] = None
    birthday: Optional[datetime.date] = None

because it will provide None to not provided arguments and it will update fields in database with None.

I don't want these fields be updated in database, so I don't need them being initialized in dataclass.

1

There are 1 best solutions below

0
Ritvik The God On

I would suggest to check out dataclass-wizard, to see if it can work for your use case. It supports skip_defaults argument when serializing a dataclass instance to JSON using to_dict, which behaves very similar to the builtin dataclasses.asdict.

You can use to_dict() method when saving modified fields (only values passed in to the __init__() constructor method) to database, as shown below.

Disclaimer: I am the creator and maintener of this library.

# Can be removed in Python 3.10+, as `X | Y` annotation syntax is supported OOTB
from __future__ import annotations

from dataclasses import dataclass
from datetime import date

from dataclass_wizard import JSONWizard


@dataclass
class Person(JSONWizard):

    # Custom config for (de)serializing a dataclass instance
    class _(JSONWizard.Meta):
        skip_defaults = True
        # optional: if you need (serialized) field names to be `snake_cased`
        # key_transform_with_dump = 'SNAKE'

    # REQUIRED
    id: int
    # (NOT) REQUIRED
    first_name: str | None = None
    last_name: str | None = None
    birthday: date | None = None


person = Person(id=1, first_name='Andrew')

# Print the `__repr__()` of class instance
print(repr(person))
print()

# Print the update data (for database)
print(person.to_dict())

Prints:

Person(id=1, first_name='Andrew', last_name=None, birthday=None)

{'id': 1, 'firstName': 'Andrew'}