python xmlrpc-odoo

4
Python 基于xmlrpcwebservice服务以及在odoo中的使用 XML-RPC通过xml来传输RPC,在Python中提供了xmlrpclib模块进行了封装。参考文 https://docs.python.org/2/library/xmlrpclib.html 一个简单的例子 from SimpleXMLRPCServer import SimpleXMLRPCServer class HelloService: def sayHello(self, name): return "Hello " + name; def start_server(): obj = HelloService() server = SimpleXMLRPCServer(("localhost", 8080)) server.register_instance(obj) server.serve_forever() print "Server Started...." 上面的例子作为服务端采用了SimpleXMLRPCServer,需要指定hostport即可。在这个例子里注册了一个对象实例,接下来看看 客户端的写法 import xmlrpclib def helloClient(): server = xmlrpclib.ServerProxy("http://localhost:8080") words = server.sayHello("Python") print "result: %s" % (words,) 这样就完成了一个请求的过程。当然这只是一个很简单的例子,上面是注册实例,那么对象里面的方法都可以访问。同样也支持对 函数的注册 将函数作为服务发布 def division(x, y): return x / y def server_reg_func(): server = SimpleXMLRPCServer(("localhost", 8080)) server.register_function(division, "division") server.serve_forever() print "Server Started...." 将函数作为服务发布采用了方法 register_function ,需要传入参数函数和调用的名称。那么在客户端访问和上面例子基本一致, 只需要调用函数名为注册的( division )即可 server.division(2, 5) 。上面的例子只注册了一个函数发布服务,在现实世界中可能 会有多个服务,那也是支持的 注册多个函数作为服务发布 def server_multi_funcs(): server = SimpleXMLRPCServer(("localhost", 8080)) server.register_multicall_functions() server.register_function(division, "division") server.register_function(add, "add") server.serve_forever() print "Server Started...." 这里新增了函数 register_multicall_functions 调用,那么就支持同时注册多个函数发布服务,这是在客户端需要做一些调整,不 会直接返回结果而是将调用的结果作为实例返回 def multi_fun_client(): server = xmlrpclib.ServerProxy("http://localhost:8080") multicall = xmlrpclib.MultiCall(server) try: multicall.division(2, 5) multicall.add(2, 0) result = multicall() print type(result) print "2/5=%d, 2+0=%d" % tuple(result)

Upload: robin-yang

Post on 15-Jan-2015

299 views

Category:

Technology


6 download

DESCRIPTION

python webservice base on xmlrpc and used in odoo

TRANSCRIPT

Page 1: Python xmlrpc-odoo

Python基于xmlrpc的webservice服务以及在odoo中的使用XML-RPC通过xml来传输RPC,在Python中提供了xmlrpclib模块进行了封装。参考文档https://docs.python.org/2/library/xmlrpclib.html

一个简单的例子

from SimpleXMLRPCServer import SimpleXMLRPCServer

class HelloService:

def sayHello(self, name): return "Hello " + name;

def start_server(): obj = HelloService() server = SimpleXMLRPCServer(("localhost", 8080)) server.register_instance(obj) server.serve_forever() print "Server Started...."

上面的例子作为服务端采用了SimpleXMLRPCServer,需要指定host和port即可。在这个例子里注册了一个对象实例,接下来看看客户端的写法

import xmlrpclib

def helloClient(): server = xmlrpclib.ServerProxy("http://localhost:8080") words = server.sayHello("Python") print "result: %s" % (words,)

这样就完成了一个请求的过程。当然这只是一个很简单的例子,上面是注册实例,那么对象里面的方法都可以访问。同样也支持对

函数的注册

将函数作为服务发布

def division(x, y): return x / y

def server_reg_func(): server = SimpleXMLRPCServer(("localhost", 8080)) server.register_function(division, "division") server.serve_forever() print "Server Started...."

将函数作为服务发布采用了方法register_function,需要传入参数函数和调用的名称。那么在客户端访问和上面例子基本一致,只需要调用函数名为注册的(division)即可server.division(2, 5)。上面的例子只注册了一个函数发布服务,在现实世界中可能会有多个服务,那也是支持的

注册多个函数作为服务发布

def server_multi_funcs(): server = SimpleXMLRPCServer(("localhost", 8080)) server.register_multicall_functions() server.register_function(division, "division") server.register_function(add, "add") server.serve_forever() print "Server Started...."

这里新增了函数register_multicall_functions调用,那么就支持同时注册多个函数发布服务,这是在客户端需要做一些调整,不会直接返回结果而是将调用的结果作为实例返回

def multi_fun_client(): server = xmlrpclib.ServerProxy("http://localhost:8080") multicall = xmlrpclib.MultiCall(server) try: multicall.division(2, 5) multicall.add(2, 0) result = multicall() print type(result) print "2/5=%d, 2+0=%d" % tuple(result)

Page 2: Python xmlrpc-odoo

print "2/5=%d, 2+0=%d" % tuple(result) except xmlrpclib.Fault as err: print "A fault occurred" print "Fault code: %d" % err.faultCode print "Fault string: %s" % err.faultString

这里还显示了发生错误时相应的提示信息

多线程的服务

多线程服务也很简单,在服务端提供了相关的接口

class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer): pass

def server_thread(): server = ThreadXMLRPCServer(("localhost", 8080)) server.register_function(division, "division") server.serve_forever()

这样服务端就能作为一个多线程处理请求,他会将每个请求一个线程进行处理

多路径服务

在前面的例子中我们都是在同一个端口下发布的服务,但是并没指定路径。对多路径的支持如下

class RequestHandler(SimpleXMLRPCRequestHandler): rpc_paths = ('/','/hello')

def server_path(): server = SimpleXMLRPCServer(("localhost", 8080), requestHandler=RequestHandler) server.register_function(add, "add") server.serve_forever() print "Server Started...."

这里服务端新增了处理请求的Handler他会将根目录指向到/hello路径下,在客户端就可以用这个路径进行访问

def path_client(): server = xmlrpclib.ServerProxy("http://localhost:8080/hello") print server.add(2, 5)

二进制文件的读取

在python官方DOC中提供了传输二进制文件的例子

from SimpleXMLRPCServer import SimpleXMLRPCServerimport xmlrpclib

def python_logo(): with open("python_logo.jpg", "rb") as handle: return xmlrpclib.Binary(handle.read())

server = SimpleXMLRPCServer(("localhost", 8000))print "Listening on port 8000..."server.register_function(python_logo, 'python_logo')

server.serve_forever()

客户端读取文件并写入本地

import xmlrpclib

proxy = xmlrpclib.ServerProxy("http://localhost:8000/")with open("fetched_python_logo.jpg", "wb") as handle: handle.write(proxy.python_logo().data)

odoo中webservice的使用

odoo中的webservice采用基于xmlrpc的实现提供了内置的实现,我们在暴露接口的时候只需要调用相关的方法就可以实现。

获取用户信息获取用户信息

传入dbname,name和password。返回uid。注意请求的路径为host:prot/xmlrpc/common

Page 3: Python xmlrpc-odoo

传入dbname,name和password。返回uid。注意请求的路径为host:prot/xmlrpc/common

server_conf = xmlrpclib.ServerProxy("http://localhost:8069/xmlrpc/common")uid = server_conf.login("open_erp", "admin", "admin")

新建一条记录新建一条记录

对象的操纵请求路径都为host:prot/xmlrpc/object,需要传入参数dbname,uid,db_password可变的参数为需要创建对象的name属性(dili.pos.psam),方法,这里是新建(create),其他包括查询(search),读取(read),更新(write),删除(unlink)

server = xmlrpclib.ServerProxy("http://localhost:8069/xmlrpc/object")psam = { 'name' : 'abc', 'rsa_public_key' : 'jjjjj' } result = server.execute("open_erp", uid, "root", "dili.pos.psam", "create", psam)

查询、读取、更新和删除查询、读取、更新和删除

查询中支持查询参数(query_args)返回满足结果的id列表。读取中支持需要返回数据的字段(fields)返回满足条件的列表。更新则需要传入需要更新数据的编号列表,同时values对应了更改的编号返回执行结果True或False

删除需要传入删除id列表,返回执行的结果True或False

server = xmlrpclib.ServerProxy("http://localhost:8069/xmlrpc/object")query_args = [('name', '=', 'abc'), ('rsa_public_key', '=', 'jjjjj')]ids = server.execute("open_erp", uid, "root", "dili.pos.psam", "search", query_args)

fields = ['name', 'rsa_public_key', 'psam_rsa']datas = server.execute("open_erp", uid, "root", "dili.pos.psam", "read", ids, fields)

values = {'name':'abcd'}success = server.execute("open_erp", uid, "root", "dili.pos.psam", "write", ids, values)

success = server.execute("open_erp", uid, "root", "dili.pos.psam", "unlink", ids)

odoo中实现简述

接下来看看基于wsgi中的实现。我们可以从openerp-wsgi.py中工程启动使用了application函数

application = openerp.service.wsgi_server.application

在wigi_server.py中函数的定义指明了处理的方式

def application(environ, start_response): if config['proxy_mode'] and 'HTTP_X_FORWARDED_HOST' in environ: return werkzeug.contrib.fixers.ProxyFix(application_unproxied)(environ, start_response) else: return application_unproxied(environ, start_response)

在函数application_unproxied中采用了解析handler:wsgi_xmlrpc以及更多注册的。这里关注wsgi_xmlrpc

def wsgi_xmlrpc(environ, start_response): """ Two routes are available for XML-RPC

/xmlrpc/<service> route returns faultCode as strings. This is a historic violation of the protocol kept for compatibility.

/xmlrpc/2/<service> is a new route that returns faultCode as int and is therefore fully compliant. """ if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/xmlrpc/'): length = int(environ['CONTENT_LENGTH']) data = environ['wsgi.input'].read(length)

# Distinguish betweed the 2 faultCode modes string_faultcode = True if environ['PATH_INFO'].startswith('/xmlrpc/2/'): service = environ['PATH_INFO'][len('/xmlrpc/2/'):] string_faultcode = False

Page 4: Python xmlrpc-odoo

else: service = environ['PATH_INFO'][len('/xmlrpc/'):]

params, method = xmlrpclib.loads(data) return xmlrpc_return(start_response, service, method, params, string_faultcode)

这里有两点:

1、只处理post请求和请求路径中有/xmlprc即处理基于xmlrpc的请求2、可以采用2中路径,区别是错误码返回int和字符串具体处理请求在函数xmlrpc_return中

result = openerp.http.dispatch_rpc(service, method, params)

在改方法中处理了几种service的情况

if service_name == 'common': dispatch = openerp.service.common.dispatchelif service_name == 'db': dispatch = openerp.service.db.dispatchelif service_name == 'object': dispatch = openerp.service.model.dispatchelif service_name == 'report': dispatch = openerp.service.report.dispatchelse: dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name)result = dispatch(method, params)