如何从 url 获取 Put 路由和 Delete 的 ID

How to get ID from url for Put route and Delete

我试图将所有 crud 方法放在 python Tornado 框架中的一个处理程序 class 下。 Post()get() 有效,但由于某些原因无法定义 carId。我可以将 api 端点的 ID 传递给该方法的一种方法是什么。 放置和删除的端点:api/cars/1

Error: TypeError: put() missing 1 required positional argument:
'carId' ERROR:tornado.access:500 PUT /api/cars/1 (::1) 0.50ms

方法:

    # Delete method that deletes data specified by HTTP client from database
    def delete(self, carId):

        try:
            data = json.loads(self.request.body)
            print(data)
            print("Deleting Car")
            id = data["id"]
            if not carId:
                return self.write({"success": False})
            if not len(id):
                return self.write({"success": False})
            c.execute(
                "DELETE FROM cars WHERE id=?",(carId))
            self.write({"success": 200})
        except:
            self.write({"success": False})
        conn.commit()

    # Put route to edit an entity in DB.
    def put(self, carId):

        try:
            data = json.loads(self.request.body)
            print(data)
            print("Updating Cars table")
            id = data["id"]
            make = data["make"]
            model = data["model"]
            if not make or not model or not carId:
                return self.write({"success": False})
            if not len(make) or not len(model):
                return self.write({"success": False})
            c.execute(
                "UPDATE cars SET make=?, model=? WHERE id=?",(make, model, id))
            self.write({"success": 200})
        except:
            self.write({"success": False})
        conn.commit()


def verifyDatabase():
    try:
        c.execute('SELECT * FROM cars')
        print('Table already exists')
    except:
        print('Creating table \'cars\'')
        c.execute('CREATE TABLE cars (\
            id integer primary key,\
            make text,\
            model text)')
        print('Successfully created table \'cars\'')
    conn.commit()

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", MainHandler),
            (r"/api/cars/?", CarHandler),
            (r"/api/cars/[0-9]/?", CarHandler)
        ]
        tornado.web.Application.__init__(self, handlers)

def main():

    # Verify the database exists and has the correct layout
    verifyDatabase()

    app = Application()
    app.listen(80)
    IOLoop.instance().start()
    conn.close()
if __name__ == '__main__':
    main()

您需要在正则表达式中使用 捕获组 来告诉 Tornado 将哪些部分传递给您的方法。在 carId:

对应的部分加上括号
 (r"/api/cars/([0-9])/?", CarHandler)

请注意,carId 将作为字符串传递,因此您可能需要将其转换为 carId = int(carId)。 (此外,除非您的汽车 ID 只能是个位数,否则您可能需要 ([0-9]+)

解释错误: 这条路线 (r"/api/cars/?", CarHandler) 指向 CarHandler 但它没有向处理程序的方法传递任何参数。我相信 get 和 post 方法是这样定义的:def get(self):,所以它们真的不需要任何参数;另一方面,put 和 delete 方法定义为 def put(self, carId):,因此它们需要获取参数。出于这个原因,你得到了错误: Error: TypeError: put() missing 1 required positional argument: 同样,(r"/api/cars/[0-9]/?", CarHandler) 也没有传递参数。

修复路由错误: 首先,正如另一位成员所解释的那样,您需要修复 (r"/api/cars/[0-9]/?", CarHandler) 才能将参数传递给您的方法。您只需在路线中输入 () 即可。应该是这样的:(r"/api/cars/([0-9])/?", CarHandler).

修复方法定义错误: 你可以看到,即使你按照我说的去做,你可能仍然会遇到同样的错误。问题是所有路由都指向处理程序中的所有方法。因此处理程序的方法应该具有相同的方法签名,或者它们应该能够以相同的方式被调用。

这一点有点棘手。 PUT 和 DELETE 方法期望获得 carId,但并非所有路由都传递 carId 作为参数((r"/api/cars/?", CarHandler) 不是)。这个路由调用方法是这样的:self.method();它适用于 self.get()self.post(),但一旦他们期待争论,就无法放置或删除。您可以修复它,将您的处理程序一分为二或将您的方法定义更改为:

def delete(self, carId=None):
    ...

def put(self, carId=None):
    ...

并添加一些逻辑验证作为 if carId is None: return