FastAPI / sqlite3.InterfaceError: Ошибка привязки параметра 0 - возможно, неподдерживаемый тип - PullRequest
0 голосов
/ 03 мая 2020

Мне нужно создать конечную точку, которая позволит мне редактировать данные клиентов (компания, адрес, город, штат, страна, почтовый индекс, факс - не все поля клиентов .schema). Конечная точка должна иметь возможность принимать объект json со следующими полями. Мне нужно убедиться, что клиент с указанным идентификатором существует в таблице клиентов. В ответ приложение с кодом 200 должно вернуть объект клиента. Я имею эту досадную ошибку, которую я не мог решить. Вот моя функция:

import aiosqlite
from fastapi import APIRouter, Response, status
from pydantic import BaseModel

class Customer(BaseModel):
    company: str = None
    address: str = None
    city: str = None
    state: str = None
    country: str = None
    postalcode: str = None
    fax: str = None

router = APIRouter()
@router.on_event("startup")
async def startup():
    router.db_connection = await aiosqlite.connect('chinook.db')


@router.on_event("shutdown")
async def shutdown():
    await router.db_connection.close()

@router.put("/customers/{customer_id}")
async def update_customer(response: Response, customer_id: int, customer: Customer):
    cursor = await router.db_connection.execute(
        "SELECT CustomerId FROM customers WHERE CustomerId = ?", (customer_id, )
    )
    customer_id = await cursor.fetchone()
    if not customer_id:
        response.status_code = status.HTTP_404_NOT_FOUND
        return {"detail": {"error": "No customer found with the given customer_id!"}}
    update_date = customer.dict(exclude_unset=True)
    if update_date:
        sql = "UPDATE customers SET "
        for key, value in update_date.items():
            if key == "postalcode":
                key = "PostalCode"
            key = key.capitalize()
            sql += f"{key} = '{value}', "
        sql = sql[:-2] + f" WHERE CustomerId = {customer_id}"
        cursor = await router.db_connection.execute(sql)
        await router.db_connection.commit()
    router.db_connection.row_factory = aiosqlite.Row
    cursor = await router.db_connection.execute(
        "SELECT * FROM customers WHERE CustomerId = ?", (customer_id, )
    )
    customer = await cursor.fetchone()
    return customer


sqlite> .schema customers
CREATE TABLE IF NOT EXISTS "customers"
(
    [CustomerId] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    [FirstName] NVARCHAR(40)  NOT NULL,
    [LastName] NVARCHAR(20)  NOT NULL,
    [Company] NVARCHAR(80),
    [Address] NVARCHAR(70),
    [City] NVARCHAR(40),
    [State] NVARCHAR(40),
    [Country] NVARCHAR(40),
    [PostalCode] NVARCHAR(10),
    [Phone] NVARCHAR(24),
    [Fax] NVARCHAR(24),
    [Email] NVARCHAR(60)  NOT NULL,
    [SupportRepId] INTEGER,
    FOREIGN KEY ([SupportRepId]) REFERENCES "employees" ([EmployeeId]) 
                ON DELETE NO ACTION ON UPDATE NO ACTION
);
CREATE INDEX [IFK_CustomerSupportRepId] ON "customers" ([SupportRepId]);
sqlite> 


Ошибка выглядит следующим образом:


INFO:     127.0.0.1:49752 - "PUT /customers/1 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 385, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/fastapi/applications.py", line 149, in __call__
    await super().__call__(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/applications.py", line 102, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/routing.py", line 550, in __call__
    await route.handle(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/fastapi/routing.py", line 165, in app
    raw_response = await run_endpoint_function(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/fastapi/routing.py", line 119, in run_endpoint_function
    return await dependant.call(**values)
  File "./routers/tracks.py", line 109, in update_customer
    cursor = await router.db_connection.execute(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/aiosqlite/core.py", line 209, in execute
    cursor = await self._execute(self._conn.execute, sql, parameters)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/aiosqlite/core.py", line 167, in _execute
    return await future
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/aiosqlite/core.py", line 153, in run
    result = function()
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.

Пожалуйста, помогите мне, я новичок.

1 Ответ

1 голос
/ 03 мая 2020

Я думаю, что проблема в этом разделе кода:

    cursor = await router.db_connection.execute(
        "SELECT CustomerId FROM customers WHERE CustomerId = ?", (customer_id, )
    )
    customer_id = await cursor.fetchone()
    if not customer_id:
        response.status_code = status.HTTP_404_NOT_FOUND
        return {"detail": {"error": "No customer found with the given customer_id!"}}

cursor.fetchone() возвращает строку, а не одно значение, поэтому этот раздел изменяет тип значения в переменной customer_id из int в строке. *

Что вы, вероятно, хотите сделать вместо этого, это использовать другую переменную в проверке для существующего клиента. Это оставляет customer_id, как это было. Я использовал customer_row в качестве этой новой переменной в двух строках ниже. Его не нужно использовать где-либо еще: если мы вообще получим строку от этого курсора, единственное значение, которое он содержит, будет идентификатором клиента, который у нас уже есть:

    cursor = await router.db_connection.execute(
        "SELECT CustomerId FROM customers WHERE CustomerId = ?", (customer_id, )
    )
    customer_row = await cursor.fetchone()
    if not customer_row:
        response.status_code = status.HTTP_404_NOT_FOUND
        return {"detail": {"error": "No customer found with the given customer_id!"}}

* Я намеренно немного расплывчато в том, что я имел в виду под «строкой» выше. Согласно документации aiosqlite , cursor.fetchone() возвращает необязательный sqlite3.Row, но когда я запустил этот код, он вернул кортеж. Я не уверен, что это имеет огромное значение в любом случае: дело в том, что ни Row s, ни кортежи не являются int s.

...