如何使用原始SQL查询实现搜索功能

时间:2019-07-19 22:59:42

标签: python sql flask jinja2

我正在创建一个由CS50的网络系列指导的应用程序,它要求我仅使用原始SQL查询而不是ORM。

我正在尝试提供一种搜索功能,用户可以在其中查找存储在数据库中的书籍列表。我想让他们查询名为“ books”的表中的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查询和会话。

2 个答案:

答案 0 :(得分:0)

我为您创建了一个具有完整解决方案的github :)

https://github.com/researcher2/stackoverflow_57120430

几件事:

避免SQL注入

我建议在执行原始sql语句时使用绑定,我的代码反映了这一点。我花了很长时间尝试使它与您的陈述相符,然后才绊倒:

Python SQLite parameter substitution with wildcards in LIKE

基本上,您不能将绑定放在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")

答案 1 :(得分:0)

感谢您选择的答案。 通过一个简单的更改即可解决该问题。

我需要在SQL查询行中将“ LIKE”交换为“ iLIKE”。

searchResult = db.execute("SELECT isbn, author, title FROM books WHERE isbn iLIKE '%"+searchQuery+"%' OR author iLIKE '%"+searchQuery+"%' OR title iLIKE '%"+searchQuery+"%'").fetchall()

这可能不是一个很好的解决方案,但确实解决了一个临时性问题。再次感谢那些为CS50的网络系列制作过程中遇到问题的人回答并创建github存储库的家伙!