Skip to content

[Bug]: table=True with custom registry= stores bool in model_config and leaves model unmapped #2046

Description

@baiyuxi930826

Describe the bug

Passing table=True together with a custom registry= stores the boolean table flag into model_config["registry"] instead of the registry object, and the model is left unmapped.

In sqlmodel/main.py (SQLModelMetaclass):

config_registry = get_config("registry")
if config_registry is not Undefined:
    config_registry = cast(registry, config_registry)
    # If it was passed by kwargs, ensure it's also set in config
    new_cls.model_config["registry"] = config_table   # BUG: should be config_registry
    setattr(new_cls, "_sa_registry", config_registry)
    setattr(new_cls, "metadata", config_registry.metadata)
    setattr(new_cls, "__abstract__", True)

Debug information

  • Repo checkout @ 803a3d1f6d605a1da45ed166120845ed54ce9c2a
  • Python 3.12

Repro steps

from sqlalchemy.orm import registry
from sqlmodel import SQLModel, Field

reg = registry()

class Hero(SQLModel, table=True, registry=reg):
    id: int | None = Field(default=None, primary_key=True)
    name: str

print(Hero.model_config["registry"])  # True  (expected: the registry object)
print(hasattr(Hero, "__mapper__"))    # False

# Session usage typically raises sqlalchemy.orm.exc.UnmappedClassError
# Subclassing also breaks: AttributeError: 'bool' object has no attribute 'metadata'

Default path works: class Hero(SQLModel, table=True).

Expected behavior

model_config["registry"] should hold the provided registry; the table model should be mapped like the default-registry table=True path.

Actual behavior

model_config["registry"] is True; model has no mapper; multi-registry one-shot API is unusable.

Suggested direction

new_cls.model_config["registry"] = config_registry

Also reconsider always setting __abstract__ = True when a custom registry is provided on a table=True model.

I'd be happy to prepare a PR with a regression test if this is confirmed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions