Обработка ошибок в Python-MySQL

Я запускаю небольшой веб-сервис на основе флагов python, где я хочу выполнить небольшой MySQL-запрос. Когда я получаю действительный ввод для моего SQL-запроса, все работает как ожидалось, и я получаю правильное значение обратно. Однако, если значение не сохраняется в базе данных, я получаю TypeError

    Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1478, in full_dispatch_request
    response = self.make_response(rv)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1566, in make_response
    raise ValueError('View function did not return a response')
ValueError: View function did not return a response

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

#!/usr/bin/python

from flask import Flask, request
import MySQLdb

import json

app = Flask(__name__)


@app.route("/get_user", methods=["POST"])
def get_user():
    data = json.loads(request.data)
    email = data["email"]

    sql = "SELECT userid FROM oc_preferences WHERE configkey='email' AND configvalue LIKE '" + email + "%';";

    conn = MySQLdb.connect( host="localhost",
                            user="root",
                            passwd="ubuntu",
                            db="owncloud",
                            port=3306)
    curs = conn.cursor()

    try:
        curs.execute(sql)
        user = curs.fetchone()[0]
        return user
    except MySQLdb.Error, e:
        try:
            print "MySQL Error [%d]: %s" % (e.args[0], e.args[1])
            return None
        except IndexError:
            print "MySQL Error: %s" % str(e)
            return None
    except TypeError, e:
        print(e)
        return None
    except ValueError, e:
        print(e)
        return None
    finally:
        curs.close()
        conn.close()

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

В принципе, я просто хочу вернуть значение, когда все работает правильно, и я хочу ничего не возвращать, если это не желательно с сообщением об ошибке на моем сервере. Как я могу правильно использовать обработку ошибок?

EDIT Обновлен текущий код + сообщение об ошибке.

Ответы

Ответ 1

Первый момент: у вас слишком много кода в вашем блоке try/кроме. Лучше использовать отдельные блоки try/кроме случаев, когда у вас есть два оператора (или две группы операторов), которые могут вызывать разные ошибки:

try:
    try:
        curs.execute(sql)
        # NB : you won't get an IntegrityError when reading
    except (MySQLdb.Error, MySQLdb.Warning) as e:
        print(e)
        return None

    try: 
        user = curs.fetchone()[0]
        return user
    except TypeError as e:
        print(e)
        return None

finally:
    conn.close()

Теперь вам действительно нужно ловить TypeError здесь? Если вы прочитаете трассировку, вы заметите, что ваша ошибка возникает из-за вызова __getitem__() в None (примечание: __getitem__() - реализация для оператора индекса []), что означает, что если у вас нет подходящих строк cursor.fetchone() возвращает None, так что вы можете просто проверить возвращение currsor.fetchone():

try:
    try:
        curs.execute(sql)
        # NB : you won't get an IntegrityError when reading
    except (MySQLdb.Error, MySQLdb.Warning) as e:
        print(e)
        return None

    row = curs.fetchone()
    if row:
        return row[0]
    return None

finally:
    conn.close()

Теперь вам действительно нужно ловить ошибки MySQL здесь? Предполагается, что ваш запрос хорошо протестирован и представляет собой только операцию чтения, поэтому он не должен завершаться сбоем - поэтому, если у вас что-то идет не так, то у вас, очевидно, есть большая проблема, и вы не хотите скрывать это под ковром. IOW: либо регистрируйте исключения (используя стандартный пакет logging и logger.exception()) и повторно повышайте их, либо, более просто, позволяйте им распространяться (и, в конечном итоге, компонент более высокого уровня позаботится о регистрации необработанных исключений):

try:
    curs.execute(sql)
    row = curs.fetchone()
    if row:
        return row[0]
    return None

finally:
    conn.close()

И, наконец: способ создания SQL-запроса совершенно небезопасен. Вместо этого используйте заполнители sql:

q = "%s%%" % data["email"].strip() 
sql = "select userid from oc_preferences where configkey='email' and configvalue like %s"
cursor.execute(sql, [q,])

О, да: wrt/"Функция просмотра не вернула ответ" ValueError, это потому, что ваш взгляд возвращает None во многих местах. Предполагается, что представление в колбе должно возвращать что-то, что может быть использовано в качестве ответа HTTP, и здесь None не является допустимым вариантом.