sqlite3.OperationalError:没有这样的表:main.source

时间:2018-03-09 23:18:06

标签: python flask sqlite

我正在制作一个使用Python Flask和Sqlite3的API。大多数都有效。具体做法是:

  • 所有GET端点/ SELECT查询都可以正常工作
  • 两个POST端点/ INSERT INTO查询工作

但是,其余的POST / INSERT INTO不起作用。它们都具有相同的sqlite3.OperationalError,并带有消息:

no such table: main.source

这很奇怪,因为没有一个查询使用名为" source"或" main.source"。我在execute之前打印查询,我尝试将查询复制/粘贴到sqlite3命令提示符中。当我这样做时,查询没有问题。

另一个奇怪的是,所有INSERT INTO查询都调用相同的函数来创建实际的查询(后者又调用函数来运行查询...所有查询都使用它们大多数工作)。只有部分INSERT INTO会导致此错误。

一些可能有用的信息:

摘自createdb.sql

CREATE TABLE transactions (
  id INTEGER PRIMARY KEY,
  buyer INTEGER NOT NULL,
  seller INTEGER NOT NULL,
  amount INTEGER NOT NULL,
  currency VARCHAR(6) NOT NULL,
  fee INTEGER NOT NULL,
  source INTEGER NOT NULL,
  description TEXT NOT NULL,
  status VARCHAR(40) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

插入到Python中的插入/会在execute中抛出错误:

INSERT INTO transactions (status, fee, description, source, seller, currency, amount, buyer) VALUES ('initiated', '1', 'nada', '1', '2', 'USD', '1000', '1');

来自Sqlite提示的一些内容:

sqlite> .tables
conversations  sources        users        
messages       transactions   withdrawals
sqlite> SELECT id, description FROM transactions;
1|hella mulah
2|payback
3|woohoo
sqlite> INSERT INTO transactions (status, fee, description, source, seller, currency, amount, buyer) VALUES ('initiated', '1', 'nada', '1', '2', 'USD', '1000', '1');
sqlite> 
sqlite> SELECT id, description FROM transactions;
1|hella mulah
2|payback
3|woohoo
4|nada

对于引用,这里是一个POST命令,尽管使用了大部分相同的东西,但没有错误:

INSERT INTO users (session, balance, name, firebaseToken) VALUES ('ABCDEFG', '0', 'Mr Miyagi', 'ABCDEFG');

在SO上有很多类似的问题,但这里有不重复的原因:

我考虑过的其他内容但排除在外:

我确定这最终会成为某种愚蠢的混乱,但任何关于在哪里看的想法都会受到高度赞赏。我也试过谷歌搜索这个错误,但我没有看到任何有用的东西。

---更多代码---

这是database.py

import sqlite3
import flask

import backend

def dict_factory(cursor, row):
    output = {}
    for idx, col in enumerate(cursor.description):
        output[col[0]] = row[idx]
    return output


def get_db():
    if not hasattr(flask.g, 'sqlite_db'):
        flask.g.sqlite_db = sqlite3.connect("/my/absolute/path/var/data.db"
        )
        flask.g.sqlite_db.row_factory = dict_factory
        flask.g.sqlite_db.execute("PRAGMA foreign_keys = ON;")
    return flask.g.sqlite_db


def query(query, args=(), islast=False):
    print(query) # this is where the print from before is
    cur = get_db().execute(query, args)
    rowvector = cur.fetchall()
    if islast:
        cur.close()
    return rowvector


@backend.app.teardown_appcontext
def close_db(error):
    if hasattr(flask.g, 'sqlite_db'):
        flask.g.sqlite_db.commit()
        flask.g.sqlite_db.close()

这是apiimpl.py

中选定的部分
QUERY_INSERT = "INSERT INTO"
QUERY_SELECT = "SELECT"
QUERY_UPDATE = "UPDATE"

def queryhelper(*args, **kwargs):
    sqltxt = None
    selectstr = None
    if kwargs["action"] == QUERY_INSERT:
        sqltxt = "{} {} ({}) VALUES ({});".format(
            QUERY_INSERT,
            kwargs["table"],
            ", ".join(["{}".format(x) for x in kwargs["cols"]]),
            ", ".join(["'{}'".format(x) for x in kwargs["vals"]]),
        )
        # pretty sure this next bit is not relevant but here it is anyway
        selectstr = "SELECT * FROM {} WHERE ROWID=(SELECT last_insert_rowid());".format(
            kwargs["table"],
        )
    elif kwargs["action"] == QUERY_SELECT:
        # not relevant
    elif kwargs["action"] == QUERY_UPDATE:
        # not relevant
    else:
        assert(kwargs["action"] in [QUERY_INSERT, QUERY_SELECT, QUERY_UPDATE,])
    try:
        rv = db.query(sqltxt) # this is where the error is thrown
        if selectstr:
            return db.query(selectstr)
        else:
            return rv
    except sqlite3.OperationalError as e:
        # this is where the error is caught
        return api_error("SQL error (1): {}", str(e), code=500)

def append(tablename, args):
    tabledata = TABLES().tablenamemap[tablename]
    print("tablename: " + tablename) # "tablename: transactions"
    # a bunch of error detection 
    rv = queryhelper(
        action=QUERY_INSERT,
        table=tablename,
        cols=args.keys(),
        vals=args.values(),
    )
    # not shown: potentially returning json.dumps(rv)
    return rv


def transactions_post(req):
    # a lot of stuff to turn req into validargs
    # printed validargs: {'status': 'initiated', u'fee': u'1', u'description': u'nada', u'source': u'1', u'seller': u'2', u'currency': u'USD', u'amount': u'1000', u'buyer': u'1'}
    return append("transactions", validargs)


@backend.app.route("/transactions", methods=["GET", "POST", "PUT"])
def transactions_route():
    return {
        "GET":  transactions_get,       # get list of transactions
        "POST": transactions_post,      # initiate a transaction
        "PUT":  transactions_put,       # change transaction status
    }[flask.request.method](flask.request)

P.S。这个问题的目的不是讨论实施,而是如果你想发表评论对我好。

---回应评论 -

sqlite> SELECT * FROM sqlite_master WHERE type="table" AND name="transactions";
table|transactions|transactions|4|CREATE TABLE transactions (
  id INTEGER PRIMARY KEY,
  buyer INTEGER NOT NULL,
  seller INTEGER NOT NULL,
  amount INTEGER NOT NULL,
  currency VARCHAR(6) NOT NULL,
  fee INTEGER NOT NULL,
  source INTEGER NOT NULL,
  description TEXT NOT NULL,
  status VARCHAR(40) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (buyer) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (seller) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (source) REFERENCES source(id) -- do not want to delete on CASCADE
)

1 个答案:

答案 0 :(得分:2)

看起来您正在引用基于.tables命令的不存在的表。

sqlite> .tables
conversations  sources        users        
messages       transactions   withdrawals

这个创建表语句。

CREATE TABLE transactions (
  id INTEGER PRIMARY KEY,
  buyer INTEGER NOT NULL,
  seller INTEGER NOT NULL,
  amount INTEGER NOT NULL,
  currency VARCHAR(6) NOT NULL,
  fee INTEGER NOT NULL,
  source INTEGER NOT NULL,
  description TEXT NOT NULL,
  status VARCHAR(40) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (buyer) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (seller) REFERENCES users(id), -- do not want to delete on CASCADE
  FOREIGN KEY (source) REFERENCES source(id) -- do not want to delete on CASCADE
                               -- ^ there is no source table
)

如果您将来源(ID)更改为来源(ID),那么您应该会感觉良好。