Flowing large hash values to Postgres BigInt
First Check
- [X] I added a very descriptive title to this issue.
- [X] I used the GitHub search to find a similar issue and didn't find it.
- [X] I searched the SQLModel documentation, with the integrated search.
- [X] I already searched in Google "How to X in SQLModel" and didn't find any information.
- [X] I already read and followed all the tutorial in the docs and didn't find an answer.
- [X] I already checked if it is not related to SQLModel but to Pydantic.
- [X] I already checked if it is not related to SQLModel but to SQLAlchemy.
Commit to Help
- [X] I commit to help with one of those options 👆
Example Code
from sqlalchemy import BigInteger
from typing import Optional
from sqlmodel import Field, Session, SQLModel, create_engine
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
#case A
normhash: Optional[int] = Field(default=None, index=True)
#case B
#normhash: Optional[BigInteger] = Field(default=None, index=True)
hero_1 = Hero(normhash=1559512409891417611)
engine = create_engine("postgresql://app:newbpw@somehost:5400/some_db)
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
session.add(hero_1)
session.commit()
# in case A: DataError: (psycopg2.errors.NumericValueOutOfRange) integer out of range
# (case B the code won't even finish coming up - no validator error)
session.refresh(hero_1)
print(hero_1)
Description
Using your default Hero example. Replace the fields with a hash field. Using postgres, I'm unable to set up the field for big integers. Case A: using standard int results in NumericValueOutOfRange at the psycopg2 level.
So, case B: trying to force a postgres BIGINT, using sqlalchemy BigInteger, I get:
File "pydantic/validators.py", line 715, in find_validators
RuntimeError: no validator found for <class 'sqlalchemy.sql.sqltypes.BigInteger'>, see arbitrary_types_allowed in Config
I know it involves all the different levels, but it seems like a model of use problem (and I had validator problems before that ended up being a change in the way I use sqlmodel.)
Thanks for your creation of sqlmodel - so far I've really enjoyed it along with fastapi!
Operating System
Linux
Operating System Details
No response
SQLModel Version
0.0.4
Python Version
3.8.12
Additional Context
No response
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
normhash: Optional[int] = Field(default=None, index=True, sa_column=Column(BigInteger()))
@yinziyan1206 This works if the field is not the primary key. If I want to create a primary key of type BigInteger, I get the exception:
sqlalchemy.exc.ArgumentError: Mapper mapped class Hero->hero could not assemble any primary key columns for mapped table 'hero'
e.g. with id: int = Field(default=None, index=True, sa_column=Column(BigInteger()))
Any idea how to solve this?
@unidesigner uhhhh, you can make it a column in sqlalchemy just like this:
id: int = Field( default_factory=next_val, sa_column=Column(BigInteger(), primary_key=True, autoincrement=False) )
and also, you can use sa_column_kwargs to set a column in sqlalchemy. i think it is flexible
thanks @yinziyan1206 - this did the trick!
If you want to reference an id field created in this manner as a foreign key, make sure to do it like this:
customer_id: int = Field(None, foreign_key='customer.id', sa_column=Column(BigInteger()))
If you want to reference an
idfield created in this manner as a foreign key, make sure to do it like this:customer_id: int = Field(None, foreign_key='customer.id', sa_column=Column(BigInteger()))
This doesn't create foreign key constrant because if sa_column is not undefined it is returned before any parameters are parsed. And customer_id: int = Field(None, sa_column=Column(BigInteger(), foreign_key='customer.id')) the same behavor...
To make it work you should do:
customer_id: int = Field(sa_column=Column(BigInteger(), ForeignKey('customer.id')))
Just FYI, to get the bigserial column like I wanted, I had to modify @yinziyan1206's solution a bit:
from typing import Optional
from sqlalchemy import Column, BigInteger
from sqlmodel import Field, SQLModel
class Users(SQLModel, table=True):
id: Optional[int] = Field(default=None, sa_column=Column(BigInteger(), primary_key=True, autoincrement=True))
name: str
This generates the following in postgres:
CREATE TABLE public."users" (
id bigserial NOT NULL,
name varchar NOT NULL,
PRIMARY KEY (id)
);