AttributeError: 'unicode' object has no attribute '_sa_instance_state' - python

I'm just learning how to use SQLAlchemy. I'm trying to do the following, but storing title and link in two separate tables:
temp = Submissions(title=u'Facebook Homepage', link=u'http://facebook.com')
session.add(temp)
session.flush()
transaction.commit()
via:
class Links(Base):
__tablename__ = 'links'
id = Column(Integer, primary_key=True)
link = Column(Text)
created = Column(TIMESTAMP(), default=datetime.now())
def __init__(self, link):
self.link = link
class Submissions(Base):
__tablename__ = 'submissions'
id = Column(Integer, primary_key=True)
created = Column(TIMESTAMP(), default=datetime.now())
title = Column(Text)
link_id = Column(Integer, ForeignKey('links.id'))
link = relation(Links)
def __init__(self, title, link):
self.title = title
self.link = link
However, I always get this error:
AttributeError: 'unicode' object has no attribute '_sa_instance_state'
What is going on? Is there a better way to code this?

You can't quite do that with relationship.
You need to arrange for the Link to be looked up in some way.
The most obvious is to just look it up directly.
submission_link = session.query(Links) \
.filter(Links.link == u'http://facebook.com') \
.first()
if submission_link is None:
submission_link = Links(link=u'http://facebook.com')
session.add(submission_link)
submission = Submissions(title=u'Facebook Homepage', link=submission_link)
session.add(submission)
session.commit()
You can also use hybrid attributes to get something that looks a bit more like your example, but its substantially more convoluted.
also, it's relationship, relation is deprecated.

I would configure the relation as one-to-one (uselist=False) and add a property which would wrap the link relationship. The SA configuration would then look like below and your code should work just fine creating, updating and deleting the link. You might need to configure the relation for have delete-orphan option in a cascade.
...
class Submissions(Base):
__tablename__ = 'submissions'
id = Column(Integer, primary_key=True)
created = Column(DateTime(), default=datetime.now())
title = Column(Text)
link_id = Column(Integer, ForeignKey('links.id'))
link_rel = relation(Links, backref=backref("_submission", uselist=False))
def __init__(self, title, link=None):
self.title = title
self.link = link
#property
def link(self):
return self.link_rel and self.link_rel.link
#link.setter
def link(self, value):
if value is None:
self.link_rel = None
elif self.link_rel is None:
self.link_rel = Links(value)
else:
self.link_rel.link = value
...

Related

SqlAlchemy Help: Trying to add a child to a child

I have this database schema:
class Profile_Eval(Base):
__tablename__ = 'profile_eval'
id = Column(Integer, primary_key=True)
url = Column(String(), unique=True)
job_descriptions = relationship("Job_Description", back_populates='profile')
def __init__(self, url=None):
self.url = url
class Job_Description(Base):
__tablename__ = 'job_description'
id = Column(Integer, primary_key=True)
data = Column(String())
profile_eval_id = Column(Integer, ForeignKey('profile_eval.id'))
profile = relationship("Profile_Eval", back_populates='job_descriptions')
job_predictions= relationship("Job_Prediction", back_populates='job_description')
def __init__(self, data=None, profile_eval_id=None):
self.data = data
class Job_Prediction(Base):
__tablename__ = 'job_prediction'
id = Column(Integer, primary_key=True)
label = Column(String())
score = Column(String())
job_description_id = Column(Integer, ForeignKey('job_description.id'))
job_description = relationship("Job_Description", back_populates="job_predictions")
def __init__(self, label=None, score=None, job_description_id=None):
self.label = label
self.score = score
The structure is that each profile has many jobs. Each job has many predictions.
I am able to add a profile like:
profile = Profile_Eval(url=url)
and then I am able to add the job descriptions to the profile like:
profile_record.job_descriptions.append(Job_Description(description))
but now I'm a little confused as to how I can add the predictions to each description.
Should I break it out into their own tables and get rid of the relationship? Or is there a way to add them?
Thanks!
Should I break it out into their own tables and get rid of the relationship?
The Job_Prediction is already its own table.
Or is there a way to add them?
yes, add predictions to the descriptions at the same time you're adding the descriptions to the jobs:
job_description = Job_Description(description)
job_description.job_predictions.append(...)
# ^^^ whetever you need, here
profile_record.job_descriptions.append(job_description)

sqlalchemy - how to copy deep copy a entry and all its foreign relation

Now I have a database schema:
For a video it contains many segment and for a segment its contains many jobs and in each job it contains many paths and so on...
Now I want to copy segment and combine together to make a new video. I know I could write a script to loop over from segment to jobs to... to bboxs and copy all the entry one by one. But is there a better solution that I could do the deep copy and all its foreign relation entry in a smarter way?
I tried to find a solution for this but ended up adding manual copy methods as suggested by some of the users in the comment links above but I opted for a more manual approach which, in my case, simplified things. With your example, my solution would have looked like this:
class Video(Model):
__tablename__ = 'videos'
id = Column(Integer, primary_key=True)
vidcol1 = Column(...)
vidcol2 = Column(...)
segments = relationship('Segment', uselist=True)
def copy(self):
new = Video()
new.vidcol1 = self.vidcol1
new.vidcol2 = self.vidcol2
for segment in self.segments:
new.segments.append(segment.copy())
return new
class Segment(Model):
__tablename__ = 'segments'
id = Column(Integer, primary_key=True)
video_id = Column(Integer, ForeignKey('videos.id'))
segcol1 = Column(...)
segcol2 = Column(...)
jobs = relationship('Job', uselist=True)
def copy(self):
new = Segment()
new.segcol1 = self.segcol1
new.segcol2 = self.segcol2
for job in self.jobs:
new.jobs.append(job.copy())
return new
class Job(Model):
__tablename__ = 'jobs'
id = Column(Integer, primary_key=True)
segment_id = Column(Integer, ForeignKey('segments.id'))
jobcol1 = Column(...)
jobcol2 = Column(...)
paths = relationship('Path', uselist=True)
def copy(self):
new = Job()
new.jobcol1 = self.jobcol1
new.jobcol2 = self.jobcol2
for path in self.paths:
new.paths.append(path.copy())
return new
class Path(Model):
__tablename__ = 'paths'
id = Column(Integer, primary_key=True)
job_id = Column(Integer, ForeignKey('jobs.id'))
pthcol1 = Column(...)
pthcol2 = Column(...)
bboxs = relationship('BBox', uselist=True)
def copy(self):
new = Path()
new.pthcol1 = self.pthcol1
new.pthcol2 = self.pthcol2
for bbox in self.bboxs:
new.bboxs.append(bbox.copy())
return new
class BBox(Model):
__tablename__ = 'bboxs'
id = Column(Integer, primary_key=True)
path_id = Column(Integer, ForeignKey('paths.id'))
boxcol1 = Column(...)
boxcol2 = Column(...)
def copy(self):
new = BBox()
new.boxcol1 = self.boxcol1
new.boxcol2 = self.boxcol2
return new
Each model is responsible for copying its own columns and calling the copy method of its direct relationships. This way, videos don't need to be aware of all the deeper relationships and you can do something like this:
video_copy = existing_video.copy()
session.add(video_copy)
session.commit()
In my situation I also had many-to-many relations (as secondary tables and AssociationObjects). If you wanted to add other types of relations it wouldn't be too complicated.

Flask SQLAlchemy filter records from foreign key relationship

I have 2 models:
class Scenario(db.Model):
__tablename__ = 'scenarios'
scenario_id = db.Column(db.Integer, primary_key=True)
scenario_name = db.Column(db.String(120))
scenario_text = db.Column(db.Text)
hints = db.relationship('Hint', backref='scenario', lazy='dynamic')
def __init__(self, scenario_name, scenario_text):
self.scenario_name = scenario_name
self.scenario_text = scenario_text
def __repr__(self):
return "<Scenario(scenario_name='%s', scenario_text='%s', hints='%s')>" % self.scenario_name, self.scenario_text, self.hints
class Hint(db.Model):
__tablename__ = 'hints'
hint_id = db.Column(db.Integer, primary_key=True)
scenario_id = db.Column(db.Integer, db.ForeignKey('scenarios.scenario_id'))
hint = db.Column(db.Text)
release_time = db.Column(db.Integer)
def __init__(self, scenario_id, hint, release_time):
self.scenario_id = scenario_id
self.hint = hint
self.release_time = release_time
def __repr__(self):
return "<Hint(scenario_id='%s', hint='%s', release_time='%s')>" % self.scenario_id, self.hint, self.release_time
I want to be able to get all the scenarios with their corresponding hints but only the hints that have a release_time less than the current time.
I figured this would work:
scenarios = Scenario.query.filter(Scenario.hints.release_time < time.time())
But I get this error:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Scenario.hints has an attribute 'release_time'
I just started playing around with Flask and SQLAlchemy. Any advice would be appreciated.
Scenario.hints is a query, so you'll need to use a join to perform this kind of filtering.
>>> scenarios = Scenario.query.join(Hint).filter(Hint.release_time < time.time())
>>> scenarios.first()
>>> <Scenario(scenario_name='hi', scenario_text='world', hints='SELECT hints.hint_id AS hints_hint_id, hints.scenario_id AS hints_scenario_id, hints.hint AS hints_hint, hints.release_time AS hints_release_time FROM hints WHERE :param_1 = hints.scenario_id')>
See the query docs and the ORM tutorial for more details.

SQLAlchemy Using relationship()

I am using SQLAlchemy here, trying to make a couple tables and link them and am having problems implementing this.
class Team(Base):
__tablename__ = "teams"
id = Column(Integer, primary_key=True)
espn_team_id = Column(Integer, unique=True, nullable=False)
games = relationship("Game", order_by="Game.date")
def __init__(self, name):
self.name = name
self.espn_team_id = espn_team_id
self.games = games
class Game(Base):
__tablename__ = "games"
id = Column(Integer, primary_key=True)
espn_game_id=Column(Integer, unique=True, nullable=False)
date = Column(Date)
h_espn_id = Column(Integer, ForeignKey('teams.espn_team_id'))
a_espn_id = Column(Integer, ForeignKey('teams.espn_team_id'))
I have this in one file which I use to create the tables. Then in another file I use the insert() function to put values into both tables. I think if I have a team with espn_team_id 360, and then I put in multiple games into the game table which have either h_espn_id=360, or a_espn_id=360, i should be able to do:
a = Table("teams", metadata, autoload=True)
a = session.query(a).filter(a.c.espn_team_id==360).first().games
and it should give me a list of all games team with ID 360 has played. But instead I get this error
AttributeError: 'NamedTuple' object has no attribute 'games'
What am I misunderstanding about SQLAlchemy or relational databases here?
Firstly, you don't have to create another Table object, as it is available as Team.__table__. Anyway, you can just query the mapped class, e.g.
query = Session.query(Team).filter(Team.espn_team_id == 360)
team360 = query.one()
games = team360.games
Refer to the documentation for methods .one(), .first(), and .all(): http://docs.sqlalchemy.org/en/latest/orm/query.html
Here is the solution I found, took way too long to understand this...
class Team(Base):
__tablename__ = "teams"
id = Column(Integer, primary_key=True)
name = Column(String)
espn_team_id = Column(Integer, unique=True, nullable=False)
h_games = relationship(
"Game",
primaryjoin="Game.h_espn_id==Team.espn_team_id",
order_by="Game.date")
a_games = relationship(
"Game",
primaryjoin="Game.a_espn_id==Team.espn_team_id",
order_by="Game.date")
#hybrid_property
def games(self):
return self.h_games+self.a_games
def __init__(self, name):
self.name = name
self.espn_team_id = espn_team_id
self.h_games = h_games
self.a_games = a_games
self.games = games

With SQLAlchemy, how do I make a dynamic relation?

I have a SyncEntities class (shown below).
I have several other classes (such as CommodityTypes also shown below) related to the SyncEntities class.
All of my Base subclasses have this column uuidKey = Column(String, primary_key=True)
Assume se is an instance of SyncEntities.
se.entityKind is the name of a Base subclass.
How do I query for an object that is in the se.entityKind class filtering for se.uuidKey?
class SyncEntities(Base):
__tablename__ = 'SyncEntities'
uuidKey = Column(String, primary_key=True)
dateCreated = Column(DateTime, index=True)
dateModified = Column(DateTime, index=True)
dateSynced = Column(DateTime, index=True)
username = Column(String)
entityKind = Column(String)
deleted = Column(Boolean)
def __init__(self, entity, security):
self.uuidKey = newUUID()
self.dateCreated = security.now
self.dateModified = security.now
self.dateSynced = security.then
self.username = security.username
self.entityKind = entity.__tablename__
self.deleted = False
def modified(self, security):
self.dateModified = security.now
self.username = security.username
class CommodityTypes(Base):
__tablename__ = 'CommodityTypes'
uuidKey = Column(String, ForeignKey('SyncEntities.uuidKey'), primary_key=True)
myName = Column(String, unique = True)
sortKey = Column(Integer, unique = True)
mySyncEntity = relationship("SyncEntities")
def __init__(self, security, myName, sortKey):
self.syncEntity = SyncEntities(self, security)
self.uuidKey = self.syncEntity.uuidKey
self.myName = myName
self.sortKey = sortKey
The structure here is similar, though not quite the same, as a "polymorphic association", and you can read about this pattern over at this blog post: http://techspot.zzzeek.org/2007/05/29/polymorphic-associations-with-sqlalchemy/ . It's an old post but the example at http://techspot.zzzeek.org/files/2007/discriminator_on_association.py was added later as an updated example.
This case is a little different in that an object like CommodityTypes only refers to a single SyncEntities, not multiple as in the usual polymorphic association. The SyncEntities also can only refer to a single type of related object since you have entityKind on it locally.
I would note that a potential problem with this design is that you could have rows in other tables that have a uuidKey pointing to a particular SyncEntities instance, but are not of a type that matches "entityKind". If the relationship between CommodityTypes and SyncEntities is actually one-to-one, that changes everything - this pattern is really simple joined table inheritance and you'd use the patterns described at http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html.
You also don't have backrefs between the target and SyncEntities, which is often a way to automate these styles of lookup. But you can still approximate things using a lookup of entityKind types to classes:
def lookup_related(se):
types = {
'commodity':CommodityTypes,
'foobar':FooBarTypes
}
cls = types[se.entityKind]
session = object_session(se)
return session.query(cls).filter(cls.mySyncEntity==se).all()
here's a mixin that could do it also, using a backref:
class HasSyncEntity(object):
entity_kind = None
"subclasses need to populate this"
#declared_attr
def uuidKey(cls):
return Column(String, ForeignKey("SyncEntities.uuidKey"), primary_key=True)
#declared_attr
def mySyncEntity(cls):
return relationship("SyncEntities", backref="_%s_collection" % cls.entity_kind)
CommodityTypes becomes:
class CommodityTypes(HasSyncEntity, Base):
entity_kind = "commodity"
# ...
You then add a method like this to SyncEntities, which looks up the appropriate backref, and you're done:
def get_related(self):
return getattr(self, "_%s_collection" % self.entityKind)

Categories