在下面的脚本中创建了一个简单的web服务器,并且有一个类应该将GET
数据发送到sqlite3数据库。
import SimpleHTTPServer
import SocketServer
import sqlite3
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
class DBLoggingHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super(DBLoggingHandler, self).__init__(*args, **kwargs)
self.db = sqlite3.connect('/home/cron1admin/crazysean/crazysean.db')
def do_GET(self):
self.db.execute("INSERT INTO crazysean (command, vers, path) VALUES (?, ?, ?)",
(self.command, self.request_version, self.path))
self.db.commit()
return super(DBLoggingHandler, self).do_GET()
DBLoggingHandler()
脚本的webserver部分工作正常。我在终端输出中看到GET
数据。但是,没有向我在db中创建的crazysean表写入任何内容。你认为我的脚本有什么问题,还是有其他问题?
代码已经更改,以反映我所做的更改,但它仍然没有写入数据库。
更新代码:
import SimpleHTTPServer
import SocketServer
import sqlite3
PORT = 8000
class DBLoggingHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)
self.db = sqlite3.connect('/home/cron1admin/crazysean/crazysean.db')
def do_GET(self):
self.db.execute("INSERT INTO crazysean (command, vers, path) VALUES (?, ?, ?)",
(self.command, self.request_version, self.path))
self.db.commit()
return super(DBLoggingHandler, self).do_GET()
Handler = DBLoggingHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
首先这样做:
httpd.serve_forever()
然后创建处理程序类并实例化它。
所以,你的代码不会做任何事情,直到"永远"之后。等的时间太长了
您要做的是将处理程序子类传递给服务器,以代替基类。这里有:
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
…改成这样:
Handler = DBLoggingHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
(或者只是去掉多余的行并执行httpd = SocketServer.TCPServer(("", PORT), DBLoggingHandler
)。)
您还必须将类的定义移到文件的顶部。
但是还有一个问题。
Python曾经有两种不同的类:new-style和classic。他们在几年前的3.0中修复了这个问题,但你仍然在使用2.something。
通常情况下,你可以总是使用新样式的类,而不必担心旧类型的类,但是每隔一段时间,你就会在标准库或第三方库中遇到一个仍然以旧方式制作的类,而你想要继承它。这就是这里发生的事情。所以,现在,遗憾的是,你必须学习老式的类。
旧式类不能做的事情是super
。解决这个问题的方法是显式调用基类的未绑定方法。所以,不用这个:
super(DBLoggingHandler, self).__init__(*args, **kwargs)
…你需要这个:
SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, *args, **kwargs)
对于其他super
调用也是如此。
当你得到一个关于classobj
或instance
的错误消息时,你知道这正在发生(而不是通过查看基类)。这两种类型总是意味着某个地方涉及了一个经典类。
等等,还有呢
无论哪个白痴告诉你把self.db = …
的东西放在__init__
方法中都是白痴。:)
SocketServer
处理程序是一种奇怪的类。每个新请求都构造一个新实例,__init__
方法调用handle
,直到销毁整个实例时才返回。因此,在调用基类之后放入__init__
中的任何内容都不会发生,直到为时已晚。
这里最简单的事情可能是使db
成为全局变量。在其他条件相同的情况下,全局变量很糟糕。但在这种情况下,替代方案似乎要么覆盖来自三个不同类的功能,要么将其monkeypatatch到服务器实例中,并依赖于未记录的细节来访问它。
另外,您可能希望在某个地方关闭数据库。在不关闭数据库的情况下终止程序应该不会使数据库损坏,但如果时间错误,则可能意味着丢失最后一个事务。
因为serve_forever
永远不会返回,除非你按ctrl-c,你不能把它放在那行后面;您需要一个with
语句(或finally
、except BaseException
或atexit
)。我认为sqlite3.Connection
对象直到Python的更高版本才成为上下文管理器,因此您将不得不使用closing
上下文管理器。
:
import contextlib
import SimpleHTTPServer
import SocketServer
import sqlite3
PORT = 8000
db = sqlite3.connect('/home/cron1admin/crazysean/crazysean.db')
class DBLoggingHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
db.execute("INSERT INTO crazysean (command, vers, path) VALUES (?, ?, ?)",
(self.command, self.request_version, self.path))
db.commit()
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
Handler = DBLoggingHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
with contextlib.closing(db):
httpd.serve_forever()
你错过了最后的魔语db.commit()
:)
def do_GET(self):
self.db.execute("INSERT INTO crazysean (command, vers, path) VALUES (?, ?, ?)",
(self.command, self.request_version, self.path))
self.db.commit()
return super(DBLoggingHandler, self).do_GET()
你有另一个错误,这个更大。你实际上没有调用你的代码,只是调用SimpleHTTPRequestHandler
。
完整的示例:
class DBLoggingHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(*args, **kwargs)
self.db = sqlite3.connect('/home/cron1admin/crazysean/crazysean.db')
def do_GET(self):
self.db.execute("INSERT INTO crazysean (command, vers, path) VALUES (?, ?, ?)",
(self.command, self.request_version, self.path))
self.db.commit()
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET()
Handler = DBLoggingHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
看一下顶部的例子:
https://docs.python.org/2/library/sqlite3.html您需要创建一个游标,通过游标执行语句,然后提交连接