1

I have two related classes as below:

class IP(Base):
    __tablename__ = 'ip'
    id = Column(Integer, primary_key=True)
    value = Column(String, unique=True)
    topics = relationship('Topic')


class Topic(Base):
    __tablename__ = 'topic'
    id = Column(Integer, primary_key=True)
    value = Column(String)
    ip_id = Column(Integer, ForeignKey('ip.id'))
    ip = relationship('IP')

if __name__ == '__main__':
  Base.metadata.create_all(engine)
  topics = [
      Topic(value='t1', ip=IP(value='239.255.48.1')),
      Topic(value='t2', ip=IP(value='239.255.48.1')),
      Topic(value='t3', ip=IP(value='239.255.48.1'))
      ]
  session.add_all(topics)

The above doesnt work as it tries to add different ip entries with same value. Is it possible to create or get the existing one so that I can use like below?

  topics = [
      Topic(value='t1', ip=create_or_get(value='239.255.48.1')),
      Topic(value='t2', ip=create_or_get(value='239.255.48.1')),
      Topic(value='t3', ip=create_or_get(value='239.255.48.1'))
      ]
balki
  • 26,394
  • 30
  • 105
  • 151
  • Related: http://stackoverflow.com/questions/2546207/does-sqlalchemy-have-an-equivalent-of-djangos-get-or-create – balki Dec 05 '13 at 19:59

1 Answers1

2

Sure, just create the function:

def create_or_get(value):
    obj = session.query(IP).filter(IP.value==value).first()
    if not obj:
        obj = IP(value=value)
        session.add(obj)
    return obj

Of course, it needs a session, but if you use scoped_session factory, it is straightforward. Alternatively, you might look into events, but it gets too complicated for the problem to solve.

van
  • 74,297
  • 13
  • 168
  • 171
  • Thanks. using a similar wrapper. However wish there was a direct way to do this without repeating for every table. – balki Nov 29 '13 at 22:29