python - ** 之后的参数必须是映射,而不是 SQLAlchemy 数据库中的 str

标签 python dictionary sqlalchemy fastapi

我正在构建一个连接到 SQLite 数据库的 FastAPI。 API 从 IMDB 网站抓取数据,并将其发送到 API 调用的数据库。 下面的代码在第 43 行给出了以下错误:“TypeError: sqlalchemy.sql.elements.TextClause.bindparams() **后面的参数必须是映射,而不是 str”。

import uvicorn
from fastapi import FastAPI
from bs4 import BeautifulSoup
import requests
import re
from databases import Database

app = FastAPI()

@app.get("/")
async def fetch_data():

    database = Database('sqlite+aiosqlite:///project.db')
    await database.connect()

    query3 = """DROP TABLE imdb"""
    await database.execute(query=query3)

    query = """CREATE TABLE imdb (id INTEGER PRIMARY KEY, movie_title VARCHAR(100), ratings DOUBLE(1,1), year INTEGER, cast VARCHAR(100))"""
    await database.execute(query=query)

    url = 'http://www.imdb.com/chart/top'
    response = requests.get(url)
    soup = BeautifulSoup(response.text, "html.parser")

    movies = soup.select('td.titleColumn')
    cast = [a.attrs.get('title') for a in soup.select('td.titleColumn a')]
    ratings = [b.attrs.get('data-value')
    for b in soup.select('td.posterColumn span[name=ir]')]

    for index in range(0, len(movies)):
        
        movie_string = movies[index].get_text()
        movie = (' '.join(movie_string.split()).replace('.', ''))
        movie_title = movie[len(str(index))+1:-7]
        year = re.search('\((.*?)\)', movie_string).group(1)
        id = movie[:len(str(index))-(len(movie))]
      
    values = {'id':[id],'movie_title':[movie_title],'ratings':[ratings],'year':[year],'cast':[cast]}

    query2 = "INSERT INTO imdb(id,movie_title,ratings,year, cast) VALUES (:id, :movie_title, :ratings, :year, :cast)"

    await database.execute_many(query=query2, values=values)
    
    query = "SELECT * FROM imdb"
    rows = await database.fetch_all(query=query)
    print('IMDB:', rows)
    await database.disconnect()

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=5049)

我已尝试格式化字典,但仍然遇到相同的错误。我也尝试过 list 和 map() 对象。我应该如何传入映射对象?

最佳答案

查看 Pycharm 中的代码,我在第 42 行看到一些类型不匹配:

await database.execute_many(query=query2, values=values)

特别是 values=values 部分 - 需要一个列表,但是给出一个字典..

查看 execute_many 的实现,我们可以看到它需要一个列表:

async def execute_many(
    self, query: typing.Union[ClauseElement, str], values: list) -> None:
    queries = [self._build_query(query, values_set) for values_set in values]
    async with self._query_lock:
       await self._connection.execute_many(queries)

build_query:

@staticmethod
def _build_query(
    query: typing.Union[ClauseElement, str], values: typing.Optional[dict]=None) -> ClauseElement:
    if isinstance(query, str):
        query = text(query)

        return query.bindparams(**values) if values is not None else query
    elif values: # <---- trying to unpack
        return query.values(**values) # <---- trying to unpack

    return query

请注意,如果我们只传递一个字典(而不是字典列表),方法 execute_many 如何生成查询:

def test_execute_many(values):
    queries = [('Some Random Input', values_set) for values_set in values]
    return queries

# Plain old dictionary: 
In [6]: test_execute_many({'a':1, 'b':2})
Out[6]: [('Some Random Input', 'a'), ('Some Random Input', 'b')]

# A list of one dictionary:
In [7]: test_execute_many([{'a':1, 'b':2}])
Out[7]: [('Some Random Input', {'a': 1, 'b': 2})]

现在,_build_query想要使用**values解压给它的值,但是在第一个示例中,它获取一个字符串,并且无法解压它。 .但在第二个示例中它将按预期工作。

我不确定你的其余代码是否有效(因为我没有尝试在本地运行它),但这个答案涵盖了你所询问的错误😊

关于python - ** 之后的参数必须是映射,而不是 SQLAlchemy 数据库中的 str,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75089354/

相关文章:

python - 如何在Python上非递归地实现有向图的广度优先搜索

python - Heroku 上的 Flask 数据库迁移

从嵌套字典生成列表的 Pythonic 方法

C# 字符串替换为字典

postgresql - 如何处理为 Multi-Tenancy Web 应用程序动态创建模式/表

python - 使用 SQLAlchemy 从 PostgreSQL 行对象获取单个值

python - 强制 nosetests 在以下划线开头的模块中查找 doctests

python - 如何正确地从带有空行的 CSV 导入字典?

python - 如何将杂乱的字典扁平化为列表?

python - hybrid_property 表达式中的 if 语句