(
cls, classname: str, bases: tuple[type, ...], dict_: dict[str, Any], **kw: Any
)
| 625 | |
| 626 | # Override SQLAlchemy, allow both SQLAlchemy and plain Pydantic models |
| 627 | def __init__( |
| 628 | cls, classname: str, bases: tuple[type, ...], dict_: dict[str, Any], **kw: Any |
| 629 | ) -> None: |
| 630 | # Only one of the base classes (or the current one) should be a table model |
| 631 | # this allows FastAPI cloning a SQLModel for the response_model without |
| 632 | # trying to create a new SQLAlchemy, for a new table, with the same name, that |
| 633 | # triggers an error |
| 634 | base_is_table = any(is_table_model_class(base) for base in bases) |
| 635 | if is_table_model_class(cls) and not base_is_table: |
| 636 | for rel_name, rel_info in cls.__sqlmodel_relationships__.items(): |
| 637 | if rel_info.sa_relationship: |
| 638 | # There's a SQLAlchemy relationship declared, that takes precedence |
| 639 | # over anything else, use that and continue with the next attribute |
| 640 | setattr(cls, rel_name, rel_info.sa_relationship) # Fix #315 |
| 641 | continue |
| 642 | raw_ann = cls.__annotations__[rel_name] |
| 643 | origin: Any = get_origin(raw_ann) |
| 644 | if origin is Mapped: |
| 645 | ann = raw_ann.__args__[0] |
| 646 | else: |
| 647 | ann = raw_ann |
| 648 | # Plain forward references, for models not yet defined, are not |
| 649 | # handled well by SQLAlchemy without Mapped, so, wrap the |
| 650 | # annotations in Mapped here |
| 651 | cls.__annotations__[rel_name] = Mapped[ann] |
| 652 | relationship_to = get_relationship_to( |
| 653 | name=rel_name, rel_info=rel_info, annotation=ann |
| 654 | ) |
| 655 | rel_kwargs: dict[str, Any] = {} |
| 656 | if rel_info.back_populates: |
| 657 | rel_kwargs["back_populates"] = rel_info.back_populates |
| 658 | if rel_info.cascade_delete: |
| 659 | rel_kwargs["cascade"] = "all, delete-orphan" |
| 660 | if rel_info.passive_deletes: |
| 661 | rel_kwargs["passive_deletes"] = rel_info.passive_deletes |
| 662 | if rel_info.link_model: |
| 663 | ins = inspect(rel_info.link_model) |
| 664 | local_table = getattr(ins, "local_table") # noqa: B009 |
| 665 | if local_table is None: |
| 666 | raise RuntimeError( |
| 667 | "Couldn't find the secondary table for " |
| 668 | f"model {rel_info.link_model}" |
| 669 | ) |
| 670 | rel_kwargs["secondary"] = local_table |
| 671 | rel_args: list[Any] = [] |
| 672 | if rel_info.sa_relationship_args: |
| 673 | rel_args.extend(rel_info.sa_relationship_args) |
| 674 | if rel_info.sa_relationship_kwargs: |
| 675 | rel_kwargs.update(rel_info.sa_relationship_kwargs) |
| 676 | rel_value = relationship(relationship_to, *rel_args, **rel_kwargs) |
| 677 | setattr(cls, rel_name, rel_value) # Fix #315 |
| 678 | # SQLAlchemy no longer uses dict_ |
| 679 | # Ref: https://github.com/sqlalchemy/sqlalchemy/commit/428ea01f00a9cc7f85e435018565eb6da7af1b77 |
| 680 | # Tag: 1.4.36 |
| 681 | DeclarativeMeta.__init__(cls, classname, bases, dict_, **kw) |
| 682 | else: |
| 683 | ModelMetaclass.__init__(cls, classname, bases, dict_, **kw) |
| 684 |
nothing calls this directly
no test coverage detected