tiangolo / sqlmodel

SQL databases in Python, designed for simplicity, compatibility, and robustness.
https://sqlmodel.tiangolo.com/
MIT License
13.54k stars 611 forks source link

support optional annotated field with default value #862

Open proever opened 3 months ago

proever commented 3 months ago

Currently, it is not possible to specify a SQLModel with an Optional complex type, such as a Decimal, as follows:

from decimal import Decimal
from typing import Annotated
from sqlmodel import Field, SQLModel

class PriceModel(SQLModel, table=True):
    id: int | None = Field(primary_key=True, default=None)
    price: Annotated[Decimal, Field(decimal_places=2, max_digits=9)] | None = None

Doing so results in the following error (see #67, #312) in get_sqlalchemy_type:

TypeError: issubclass() arg 1 must be a class

This PR attempts to fix this issue by adding a check in get_sqlalchemy_type for whether the type of the Field is a typing_extensions.AnnotatedAlias. If it is, instead of using the class of the AnnotatedAlias for the following comparisons (which results in the above error), it uses AnnotatedAlias.__origin__. Similarly, it infers the metadata from AnnotatedAlias.__metadata__ instead of the AnnotatedAlias itself.

In my testing, this approach seems to work well. I also added a simple test here that checks whether restrictions on an optional annotated field are enforced on the database side. It could probably be improved or extended.

proever commented 3 months ago

looks like some (many) tests are failing, I'll try to fix them!

Is this feature something that should work with Pydantic v1 too? I'm not too familiar with it.

bootc commented 4 weeks ago

I've just hit exactly this problem; is there any chance you could update your MR please @proever?