python - 如何使用原始 SQL 查询实现搜索功能
问题描述
我正在创建一个由 CS50 的网络系列指导的应用程序,它要求我只使用原始 SQL 查询而不是 ORM。
我正在尝试创建一个搜索功能,用户可以在其中查找存储在数据库中的书籍列表。我希望他们能够查询名为“书籍”的表中的 ISBN、标题、作者列
目前,它确实可以毫无问题地发出“GET”请求,但它没有返回任何数据,我认为问题出在我编写的 SQL 行上。
这是路线:
@app.route("/", methods=['GET','POST'])
def index():
# search function for books
if request.method == "GET":
searchQuery = request.form.get("searchQuery")
# return value from the search
searchResult = db.execute("SELECT isbn, author, title FROM books WHERE isbn LIKE '%"+searchQuery+"%' OR author LIKE '%"+searchQuery+"%' OR title LIKE '%"+searchQuery+"%'").fetchall()
# add search result to the list
session["books"] = []
# add the each result to the list
for i in searchResult:
session["books"].append(i)
return render_template("index.html", books=session["books"])
return render_template("index.html")
这是我的模板。
<form method="GET">
<input type="text" name="searchQuery" class="searchTerm" placeholder="What are you looking for?">
<button type="submit" class="searchButton">submit</button>
</form>
<div>
<h3>
{% for book in books %}
{{ book }}
{% endfor %}
</h3>
</div>
请问谁能发现问题?请注意,我应该使用原始 SQL 查询和会话。
解决方案
我为您创建了一个带有完整解决方案的 github :)
https://github.com/researcher2/stackoverflow_57120430
有几件事:
避免 SQL 注入
我建议在执行原始 sql 语句时使用绑定,我的代码反映了这一点。在偶然发现这个之前,我花了很长时间试图让这个与你的声明一起工作:
在 LIKE 中使用通配符替换 Python SQLite 参数
基本上,您不能将绑定放在 LIKE '%?%' 中,因为引号会导致替换标记被忽略。
相反,您只需要做 LIKE 吗?并手动构建替换。
使用会话
所有会话信息都经过 JSON 序列化,然后发送到客户端。在这种情况下,行记录不是 JSON 可序列化的。这对我来说是一个错误:
TypeError: Object of type 'RowProxy' is not JSON serializable
我可能不会在这里使用会话,因为客户端不需要意识到这一点,因为无论如何您都将为他们构建一个带有信息的漂亮 html 页面。只需使用 python 字典并将其传递给模板引擎。我的代码确实使用了会话,因为这是您开始使用的。
如果 github 出现故障:
from flask import request, render_template, session
from app import app, db
@app.route("/", methods=['GET','POST'])
def index():
if request.method == "POST":
searchQuery = request.form.get("searchQuery")
print(searchQuery)
# Avoid SQL Injection Using Bindings
sql = "SELECT isbn, author, title \
FROM book \
WHERE isbn LIKE :x \
OR author LIKE :y \
OR title LIKE :z"
# I spent an hour wondering why I couldnt put the bindings inside the wildcard string...
# https://stackoverflow.com/questions/3105249/python-sqlite-parameter-substitution-with-wildcards-in-like
matchString = "%{}%".format(searchQuery)
stmt = db.text(sql).bindparams(x=matchString, y=matchString, z=matchString)
results = db.session.execute(stmt).fetchall()
print(results)
session["books"] = []
for row in results:
# A row is not JSON serializable so we pull out the pieces
book = dict()
book["isbn"] = row[0]
book["author"] = row[1]
book["title"] = row[2]
session["books"].append(book)
return render_template("index.html", searchedFor=searchQuery, books=session["books"])
return render_template("index.html")
推荐阅读
- html - 为什么我的引导导航栏没有下降?
- java - 如何获取 ArrayList 中许多 JCheckBoxMenuItem 的状态?
- kotlin - R8 混淆后接口中 Kotlin 泛型类型参数的问题
- python - 从xml代码中提取数据并将其转换为python中的数组
- azure - 一个资源组中的资源可以被另一个资源组使用吗?
- go - 如何将字节数组传递给接受字节切片的函数?
- r - 创建一个变量,它是相对于一周中的小时和天的价格变化的平均值
- c# - 如何使用 Newtonsoft.Json 从 Json 数组中获取对象列表
- reactjs - amCharts4 中的列之间的空间
- azure - 查看实时指标时如何防止水平自动滚动?