python - sqlalchemy 的查询返回 AttributeError : 'NoneType' object

标签 python python-2.7 sqlalchemy

from pox.core import core
import pox.openflow.libopenflow_01 as of
import re
import datetime

from sqlalchemy import create_engine, ForeignKey
from sqlalchemy import Column, Date, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql.expression import exists

log = core.getLogger()

engine = create_engine('sqlite:///nwtopology.db', echo=False)
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()

########################################################################
class SourcetoPort(Base):
    """"""
    __tablename__ = 'source_to_port'
    id = Column(Integer, primary_key=True)
    port_no        = Column(Integer)
    src_address    = Column(String,index=True)

    #----------------------------------------------------------------------
    def __init__(self, src_address,port_no):
        """"""
        self.src_address = src_address    
    self.port_no     = port_no

########################################################################

#create tables
Base.metadata.create_all(engine)

class Tutorial (object):
  def __init__ (self, connection):
    self.connection = connection
    connection.addListeners(self)
    # Use this table to keep track of which ethernet address is on
    # which switch port (keys are MACs, values are ports).
    self.mac_to_port = {} 
    self.matrix={} 

    #This will keep track of the traffic matrix. 
    #matrix[i][j]=number of times a packet from i went to j

  def send_packet (self, buffer_id, raw_data, out_port, in_port):
    #print "calling send_packet"
    #Sends a packet out of the specified switch port.
    msg = of.ofp_packet_out()
    msg.in_port = in_port
    msg.data = raw_data
    # Add an action to send to the specified port
    action = of.ofp_action_output(port = out_port)
    msg.actions.append(action)
    # Send message to switch
    self.connection.send(msg)

  def act_like_hub (self, packet, packet_in):
    #flood packet on all ports
    self.send_packet(packet_in.buffer_id, packet_in.data,
                     of.OFPP_FLOOD, packet_in.in_port)

  def act_like_switch (self, packet, packet_in):
    """
    Implement switch-like behavior.
    """
    # Learn the port for the source MAC
    #print "RECIEVED FROM PORT ",packet_in.in_port , "SOURCE ",packet.src
    # create a Session
    #Session = sessionmaker(bind=engine)
    #session = Session()
    self.mac_to_port[packet.src]=packet_in.in_port
    #if self.mac_to_port.get(packet.dst)!=None:
    #print "count for dst",session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).count(),str(packet.dst)
    #if session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).count():
    if session.query(exists().where(SourcetoPort.src_address == str(packet.dst))).scalar() is not None:
           #send this packet
       print "got info from the database"
       q_res = session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).one()
       self.send_packet(packet_in.buffer_id, packet_in.data,q_res.port_no, packet_in.in_port)
           #create a flow modification message
           msg = of.ofp_flow_mod()
           #set the fields to match from the incoming packet
       msg.match = of.ofp_match.from_packet(packet)
           #send the rule to the switch so that it does not query the controller again.
           msg.actions.append(of.ofp_action_output(port=q_res.port_no))
           #push the rule
           self.connection.send(msg)
    else:
           #flood this packet out as we don't know about this node.
           print "flooding the first packet"
           self.send_packet(packet_in.buffer_id, packet_in.data,
                       of.OFPP_FLOOD, packet_in.in_port)
       #self.matrix[(packet.src,packet.dst)]+=1  
       entry = SourcetoPort(src_address=str(packet.src) , port_no=packet_in.in_port)
           #add the record to the session object
           session.add(entry)
           #add the record to the session object
           session.commit()

  def _handle_PacketIn (self, event):
    """
    Handles packet in messages from the switch.
    """
    packet = event.parsed # This is the parsed packet data.
    if not packet.parsed:
      log.warning("Ignoring incomplete packet")
      return
    packet_in = event.ofp # The actual ofp_packet_in message.

    #self.act_like_hub(packet, packet_in)
    self.act_like_switch(packet, packet_in)

def launch ():
  """
  Starts the component
  """
  def start_switch (event):
    log.debug("Controlling %s" % (event.connection,))
    Tutorial(event.connection)
  core.openflow.addListenerByName("ConnectionUp", start_switch)

当我运行上面的代码时,出现以下错误:

如果我使用的话,我面临的问题是出于某种原因

if session.query(exists().where(SourcetoPort.src_address == str(packet.dst))).scalar() is not None:

in place of count query.

#if session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).count():

从数据库中查询

q_res = session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).first()
self.send_packet(packet_in.buffer_id, packet_in.data,q_res.port_no, packet_in.in_port)

出现以下错误:

DEBUG:core:POX 0.1.0 (betta) going up...
DEBUG:core:Running on CPython (2.7.3/Aug 1 2012 05:14:39)
DEBUG:core:Platform is Linux-3.5.0-23-generic-x86_64-with-Ubuntu-12.04-precise
INFO:core:POX 0.1.0 (betta) is up.
DEBUG:openflow.of_01:Listening on 0.0.0.0:6633
INFO:openflow.of_01:[00-00-00-00-00-02 1] connected
DEBUG:tutorial:Controlling [00-00-00-00-00-02 1]
got info from the database
ERROR:core:Exception while handling Connection!PacketIn...
Traceback (most recent call last):
  File "/home/karthik/pox/pox/lib/revent/revent.py", line 234, in raiseEventNoErrors
    return self.raiseEvent(event, *args, **kw)
  File "/home/karthik/pox/pox/lib/revent/revent.py", line 281, in raiseEvent
    rv = event._invoke(handler, *args, **kw)
  File "/home/karthik/pox/pox/lib/revent/revent.py", line 159, in _invoke
    return handler(self, *args, **kw)
  File "/home/karthik/pox/tutorial.py", line 118, in _handle_PacketIn
    self.act_like_switch(packet, packet_in)
  File "/home/karthik/pox/tutorial.py", line 86, in act_like_switch
    self.send_packet(packet_in.buffer_id, packet_in.data,q_res.port_no, packet_in.in_port)
AttributeError: 'NoneType' object has no attribute 'port_no'
got info from the database
ERROR:core:Exception while handling Connection!PacketIn...

最佳答案

这一行:

if session.query(exists().where(SourcetoPort.src_address == str(packet.dst))).scalar() is not None:

始终如此。原因是,仅当没有行时,scalar()才返回None。但是,您的查询看起来像SELECT EXISTS (SELECT * FROM source_to_port WHERE source_to_port.src_address=?)。这将总是返回一行一列。因此,结果将为 TrueFalse,而不是 None

转到引发异常的行之前的行:如果没有匹配项,first() 将返回 None,因此 q_res。由于 q_resNone,因此下一行的 q_res.port_no 会引发异常。

(请注意,如果您希望在没有匹配项时抛出异常,则可以使用 one()。)

如果您期望匹配,请仔细检查您的数据和 filter_by() 条件,以确保它们正在执行您认为应该执行的操作。

不过,我建议您使用一个查询,而不是使用 first()one() 进行两次查询。使用 first(),您可以根据 q_res 是否为 None 进行分支:

q_res = session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).first()
if q_res is not None:
    print "got info from the database"
    self.send_packet(....)
    ...
else:
    print "flooding the first packet"
    ...

或者使用 one(),将“洪水”分支放入异常处理程序中:

from sqlalchemy.orm.exc import (NoResultFound, MultipleResultsFound)

try:
    q_res = session.query(SourcetoPort).filter_by(src_address=str(packet.dst)).one()
except NoResultFound:
    print "flooding the first packet"
    ...
# except MultipleResultsFound:
#     print "More than one result found! WUT?!"
else:
    print "got info from the database"
    ...

这两种方法之间的区别在于 one() 将确保有一个并且只有一个结果,而 first() 则不会不在乎是否有多个结果。

关于python - sqlalchemy 的查询返回 AttributeError : 'NoneType' object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16348493/

相关文章:

python - 我如何在错误退出后自动重新启动我的 python 代码?

python - 从 NTFS 共享导入 Linux 上的 Python 模块

python - python中的Clauset-Newman-Moore社区检测算法

python - 按日/月/年对 pandas 系列日期字符串进行分类的最有效方法?

python - 注册和登录 api 中的 Django Rest 框架

python - scipy中通过mean和std对负二项式进行参数化

python - 在字典列表中合并相同键的值

mysql - 使用 SQLAlchemy 创建时自动递增非唯一 ID

postgresql - Sqlalchemy json 数组,在数组中执行类似查询

python - sqlalchemy:为什么在将它分配给 Session 对象之前创建一个 sessionmaker?