-
-
Notifications
You must be signed in to change notification settings - Fork 688
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
How to specify a different name for the db table that a SQLModel refers to? #159
Comments
I tried manually setting |
Seems that setting class Product(SQLModel, table=True):
__tablename__ = "assets"
id: Optional[int] = Field(None, primary_key=True)
name: str I tried this based on reading this in the sqlalchemy docs: https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/table_config.html Just to confirm though: is this the recommended way to deal with the scenario? |
@taranlu-houzz SQLModel is essentially a combination of SQLAlchemy (for ORM) and Pydantic (for validation). While not explicitly documented in SQLModel, yes you right that using the You can also see in the doc tests that this attribute is asserted: https://github.com/tiangolo/sqlmodel/search?q=__tablename__ Finally, in the main codebase, you can see that unless set otherwise, the |
@chriswhite199 Thanks for the confirmation. I'd say my questions is resolved now. |
If you're using Pylance/Pyright, you should do __tablename__: str = name_in_database If you don't include the
Credit to @indivisible for #98 (comment) |
A very convenient way to change the table name generation is overriding the from sqlmodel import SQLModel as _SQLModel
from sqlalchemy.orm import declared_attr
from .utils import snake_case
class SQLModel(_SQLModel):
@declared_attr
def __tablename__(cls) -> str:
return snake_case(cls.__name__)
class HTTPProxy(SQLModel):
...
print(HTTPProxy.__tablename__)
#> http_proxy # utils.py
from functools import partial
import re
_snake_1 = partial(re.compile(r'(.)((?<![^A-Za-z])[A-Z][a-z]+)').sub, r'\1_\2')
_snake_2 = partial(re.compile(r'([a-z0-9])([A-Z])').sub, r'\1_\2')
def snake_case(string: str) -> str:
return _snake_2(_snake_1(string)).casefold() A |
I'm using Pyright and this doesn't work. When I try it I get the error
Not sure why this is happening to me but not others. Perhaps I'm on a newer version of Pyright. There are two fixes. First, use class Lineitem(SQLModel, table=True):
@declared_attr
def __tablename__(cls):
return "invoice_lineitems" Second, just tell Pyright to ignore it: __tablename__: str = ( # pyright: ignore [reportIncompatibleMethodOverride]
"invoices_legacy"
) or just: __tablename__: str = "invoices_legacy" # type: ignore I choose this last method because the others are far too verbose for something as simple as declaring the table name. This may seem hacky, but although I have to tell Pyright to ignore a number of things in sqlmodel, it's not half the file like I have to As I mentioned in #98 (comment), a more intuitive solution that would make Pyright happy might be putting the table name declaration in a class Lineitem(SQLModel, table=True):
class Meta:
tablename: str = "invoice_lineitems" |
I tried class SQLModel(_SQLModel):
@declared_attr
def __tablename__(cls) -> str:
return snake_case(cls.__name__) But
|
@kingyue737 In the base code, typing is ignored. class SQLModel(_SQLModel):
@declared_attr # type: ignore
def __tablename__(cls) -> str:
return snake_case(cls.__name__) |
What do you think of using the Pascal case instead lowercase or snake case? It can be more intuitive on foreign_key due to already class name is in pascal and cruds are in pascal either. class SQLModel(_SQLModel):
@declared_attr # type: ignore
def __tablename__(cls) -> str:
return cls.__name__
class RoleBase(SQLModel):
name: str
description: str
class Role(RoleBase, table=True):
id: uuid_pkg.UUID = Field(default_factory=uuid4, primary_key=True, index=True, nullable=False)
users: List["User"] = Relationship(back_populates="role", sa_relationship_kwargs={"lazy": "selectin"})
created_by_id: Optional[UUID] = Field(default=None, foreign_key="User.id")
created_by: "User" = Relationship(sa_relationship_kwargs={"lazy":"selectin", "primaryjoin":"Role.created_by_id==User.id"})
class UserBase(SQLModel):
first_name: str
last_name: str
email: EmailStr
class User(UserBase, table=True):
id: uuid_pkg.UUID = Field(default_factory=uuid4, primary_key=True, index=True, nullable=False)
role_id: Optional[UUID] = Field(default=None, foreign_key="Role.id")
role: Optional["Role"] = Relationship(back_populates="users", sa_relationship_kwargs={"lazy": "selectin"}) users = await db_session.execute(select(User).where(User.email == email)) |
Thanks for the help and discussion here everyone! 👏 🙇 Thanks for reporting back and closing the issue @taranlu-houzz 👍 |
I know this is closed already but just in case anyone else winds up here-- this worked without any __tablename__: typing.ClassVar[
typing.Union[str, typing.Callable[..., str]]
] = "your_table_name" |
from typing import Optional
from sqlmodel import SQLModel, Field
# If the actual db table is called `assets`, for example, how can I keep the following model named `Product` but have it refer to the correct table?
class Product(SQLModel, table=True):
__tablename__ = "product"
id: Optional[int] = Field(None, primary_key=True)
name: str If someone is trying to change
|
I know setting the table name through Is it possible to replicate the If that is something you would be willing to consider, I could try to take a look and see how hard it would be to implement. |
does it implement? |
sorry, for me your version does not work:
|
in jpa I have two entities. |
First Check
Commit to Help
Example Code
Description
Operating System
Linux, macOS
Operating System Details
No response
SQLModel Version
0.0.4
Python Version
3.10.0
Additional Context
No response
The text was updated successfully, but these errors were encountered: