0

我有一个要实例化的类,然后将其传递给 Tornado Web 模板。这两个函数都返回一个列表,但我在使类本身成为可迭代对象时遗漏了一些东西。恐怕这是我做错了根本的事情。我正在进行 REST API 调用,解析返回的 XML 并将一些数据返回到 webapp。这是代码:

API 调用:

class GetVMList:

    def __init__(self):
        user = 'contoso\\administrator'
        password = "apassword"
        url = "http://scspf:8090/SC2012/VMM/Microsoft.Management.Odata.svc/VirtualMachines?$filter=VMMServer%20eq%20'scvmm'"

        passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
        passman.add_password(None, url, user, password)
        # create the NTLM authentication handler
        auth_NTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)

        # create and install the opener
        opener = urllib2.build_opener(auth_NTLM)
        urllib2.install_opener(opener)

        # retrieve the result
        self.response = urllib2.urlopen(url)
        self.data = self.response.read()

    def name(self):
        dom = parseString(self.data)
        raw_xml = dom.getElementsByTagName('d:Name')
        clean_xml = []
        clean_data = []
        for i in raw_xml:
            clean_xml.append(i.toxml())
        for i in clean_xml:
            clean_data.append(i.replace('<d:Name>', '').replace('</d:Name>', ''))
        return clean_data

    def os(self):
        dom = parseString(self.data)
        raw_xml = dom.getElementsByTagName('d:OperatingSystem')
        clean_xml = []
        clean_data = []
        for i in raw_xml:
            clean_xml.append(i.toxml())
        for i in clean_xml:
            clean_data.append(i.replace('<d:OperatingSystem>', '').replace('</d:OperatingSystem>', ''))
        return clean_data

实例化:

class ListHandler(tornado.web.RequestHandler):
    def get(self):
        self.render('temp/search.html', data='')

    def post(self):
        vm_list = GetVMList()
        self.render('temp/search.html', data=vm_list)

然后模板包含以下内容:

{% for vm in data %}
<li>{{ vm.name }} running {{ vm.os }}</li>
{% end %}

错误是:TypeError: iteration over non-sequence。我想我需要__iter__在我的课堂上使用,但我不确定我是否完全理解它是如何工作的。

4

2 回答 2

2

我相信您__iter__在课堂上缺少定义。

于 2012-07-12T20:50:24.090 回答
1

我的建议如下:

  1. 创建一个类VM来存储有关单个 VM 的信息。它__init__应该获取您要存储的有关每个 VM 的信息,并将其设置为实例上的属性。如果您不需要任何实际代码来处理有关 VM 的数据,则可以使用 a collections.namedtuple,这样可以节省您编写__init__()方法的时间。

  2. 编写getVMs()为生成器,给定用户、密码和 URL,生成一系列VM实例。这个结果可以按原样进行迭代,或者如果您需要一个(只需将其传递给list())可以轻松转换为常规列表,或者用于创建将 VM 名称映射到操作系统的字典,反之亦然。

例如(此代码尚未经过测试):

class VM(object):
    def __init__(self, name, os):
        self.name = name
        self.os   = os

def getVMs(user, password, URL):
    passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
    passman.add_password(None, url, user, password)
    auth_NTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)
    urllib2.install_opener(urllib2.build_opener(auth_NTLM))
    dom = parseString(urllib2.urlopen(url).read())
    for vmnode in dom.getElementsByTagName('d:VM')   # the tag representing a VM
        name = vmnode.getElementsByTagName('d:Name')[0]  # get name of current VM
        name = name.replace('<d:Name>', '').replace('</d:Name>', '')
        os = vmnode.getElementsByTagName('d:OperatingSystem')[0]   # same for OS
        os = os.replace('<d:OperatingSystem>', '').replace('</d:OperatingSystem>', ''))
        yield VM(name, os)

...您还可以为您的 VM 对象提供名称和操作系统的 XML,或整个 VM 的 XML,但此示例实现仅将名称和操作系统作为字符串。

(有更好的方法来获取 DOM 节点的内容,而无需使用空白字符串替换 XML 标记,但我现在没有时间这样做。)

调用它:

user = r"contoso\administrator"
pass = "apassword"
url  = ("http://scspf:8090/SC2012/VMM/Microsoft.Management.Odata.svc"
        "/VirtualMachines?$filter=VMMServer%20eq%20'scvmm'")

vmlist = list(getVMs(user, pass, url))

或者只打印每个信息VM而不存储中间列表:

for vm in getVMs(user, pass, url):
    print vm.name, vm.os

或者为 VM 实例构建名称字典(假设 Python 的最新版本具有 dict 理解):

vmdict = {vm.name: vm for vm in getVMs(user, pass, url)}

使用生成器模型使其对调用者具有最大的灵活性。即使那个来电者是你,它也会让你的生活更轻松。

于 2012-07-12T23:55:53.723 回答