Search code examples
pythonsqlalchemy

Why does SQLAlchemy recommend using built-in `id` as column name?


Using reserved keywords or built-in functions as variable/attribute names is commonly seen as bad practice. However, the SQLALchemy tutorial is full of exampled with attributes named id.

Straight from the tutorial

>>> class User(Base):
...     __tablename__ = "user_account"
...
...     id: Mapped[int] = mapped_column(primary_key=True)
...     name: Mapped[str] = mapped_column(String(30))
...     fullname: Mapped[Optional[str]]
...
...     addresses: Mapped[List["Address"]] = relationship(
...         back_populates="user", cascade="all, delete-orphan"
...     )
...
...     def __repr__(self) -> str:
...         return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"

Why is it not recommended to use id_ instead, as recommended at least for keywords in PEP 8?


Solution

  • Firstly, id is not a keyword; if it was one, you would get a syntax error (try replacing id there with e.g. pass). It is a global identifier for a built-in function. And while it is a bad practice to clobber over the default identifiers defined by Python, note that id: Mapped[int] = mapped_column(primary_key=True) inside a class definition defines a static attribute of that class, not a global variable. The global function id is not the same as the static attribute User.id (or self.id, as it is used later) — there is no conflict there.

    class Foo:
        id = 42
    
    print(Foo.id)
    # => 42
    print(id)
    # => <built-in function id>
    

    However, as you correctly note:

    id = "YOU SHOULDN'T DO THIS"
    print(id)
    # => YOU SHOULDN'T DO THIS
    # (and not <built-in function id>)
    

    Secondly, as to why id is used: SQLAlchemy maps classes to SQL tables with the snakecased class name, and attributes to SQL columns with the as-is attribute name (unless you specifically say id_: mapped_column('id', primary_key=True)), so id and id_ would be different columns in SQL.

    id (as opposed to id_) is the conventional name of the primary key column in SQL (if there is a single-column primary key). Some people would name the column user_id, but many dislike having user_id in table called users, since it should be obvious what users.id, and so users.user_id is redundant; the form user_id is generally reserved for foreign keys. The SQLAlchemy examples merely follow this SQL convention.