asyncpg.исключения.Ошибка данных: недопустимый ввод для аргумента запроса $ 1: 217027642536 (значение вне диапазона int32)

#python #postgresql #sqlalchemy #fastapi #pydantic

#python #postgresql #sqlalchemy #fastapi #pydantic

Вопрос:

Я работаю над проектом, который использует FastAPI наряду с Pydantic и SQLAlchemy. Я также использую encode / databases для управления подключениями к базе данных. Но по какой-то странной причине я получаю asyncpg.exceptions.DataError: invalid input for query argument $1: 217027642536 (value out of int32 range) всякий раз, когда пытаюсь сохранить в базе данных. Вот как выглядит мой код:

database.py

 ...
...
currencies = Table(
    'currencies',
    metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('price', Float),
    Column('price_date', DateTime),
    Column('price_timestamp', DateTime),
    Column('market_cap', Integer)
)

database = Database(DATABASE_URL)
  

database_manager.py

 ...
...
async def add_currency(payload: Currency):
    query = currencies.insert().values(**payload.dict())
    return await database.execute(query=query)
  

endpoints.py

 ...
...
@endpoints.post('/', response_model=CurrencyOutput, status_code=201)
async def add_currency():
    data = check_currency_price()

    payload = Currency(
        name=data['name'],
        price=data['price'],
        price_date=data['price_date'],
        price_timestamp=data['price_timestamp'],
        market_cap=data['market_cap']
    )

    currency_id = await database_manager.add_currency(payload)
    response = {
        'id': currency_id,
        **payload.dict()
    }

    return response
  

models.py

 ...
...
class Currency(BaseModel):
    name: str
    price: float
    price_date: datetime
    price_timestamp: datetime
    market_cap: int


class CurrencyOutput(Currency):
    id: int
  

services.py

 def check_currency_price():
    response = httpx.get(
        'https://api.nomics.com/v1/currencies/ticker?'  
        'key=somerandomAPIkeyamp;ids=BTCamp;interval=1d,30damp;convert=USD'
    )

    return response.json()[0]
  

Я не вижу в этом ничего плохого. Кто-нибудь, пожалуйста, скажите мне, что, черт возьми, происходит?

Ответ №1:

По сути, у вас переполнение целых чисел, Int32 представляет 2^31 - 1 , это означает, что он может хранить значения в диапазоне от -2147483648 до 2147483648, но значение, которое вы пытаетесь вставить, больше, чем 2^31

 2**31 > 217027642536
Out: False
  

Итак, вам нужно использовать тип SQLAlchemy BigInteger, представляющий Int64, который также представляет 2^63 - 1 , который может хранить значения в диапазоне отрицательных и положительных 9,223,372,036,854,775,807

 from sqlalchemy import BigInteger

currencies = Table(
    'currencies',
    metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String(50)),
    Column('price', Float),
    Column('price_date', DateTime),
    Column('price_timestamp', DateTime),
    Column('market_cap', BigInteger)
)                        ^^^^^^^^^^
  

Изменение типа столбца market с помощью BigInteger должно решить проблему, но будьте осторожны, большие типы используют больше памяти.

Комментарии:

1. Большое вам спасибо за это! Но я все еще получал ошибку после использования BigInteger

2. Да, это так. Это то же самое

3. Если у вас установлен pgadmin, вы можете подтвердить, что ваша таблица по-прежнему использует целочисленный тип для этого столбца, поскольку она создана таким образом, вам следует снова изменить тип данных столбцов или, если у вас нет данных в этой таблице, вы можете создать ее заново.

4. Хммм, это правда. Позвольте мне попробовать воссоздать

5. Для изменения типа столбца вы можете использовать ALTER TABLE currencies ALTER COLUMN market_cap TYPE bigint