我正在尝试创建一个系统,其中 Person 是 WorkGroup 的一部分,而每个 WorkGroup 包含许多 Person s。 人还包含以前匹配的人的列表。下面是我到目前为止,我能够成功加载测试名称。但是,在 findPartner 方法中,我尝试将新的工作组分配给 Person workGroup 字段,如下所示:
self.workGroup = WorkGroup(self, newPartner)
我收到错误消息:
AttributeError: 'list' object has no attribute '_sa_instance_state'
让我感到困惑。 (我在列表后添加了更完整的堆栈跟踪)。希望有人可以指出错误(我只使用SQLAlchemy大约24小时,所以我怀疑它是基本的东西)。
def sanitize(first, last):
def san(nm):
return " ".join([part.strip().capitalize().replace(",", "")
for part in nm.split()])
return san(first) + " " + san(last)
class Person(db.Model):
__tablename__ = 'person'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True)
workGroup = db.relationship("WorkGroup", uselist=False)
prevPairings_id = db.Column(db.Integer, db.ForeignKey('person.id'))
prevPairings = db.relationship('Person')
def __init__(self, first, last):
self.name = sanitize(first, last)
self.workGroup = None
self.prevPairings = []
def __repr__(self):
return self.name
def findPartner(self, amongPeople):
if self.workGroup:
return # You already have a group
candidates = [p for p in amongPeople if p is not self and
p not in self.prevPairings and not p.workGroup]
assert candidates
newPartner = candidates[0] # Just choose the first available
self.prevPairings.append(newPartner)
newPartner.prevPairings.append(self)
self.workGroup = WorkGroup(self, newPartner)
newPartner.workGroup = self.workGroup
def show(self):
print "<Person %r %r %r %r>" % (self.id, self.name, self.prevPairings, self.workGroup)
class WorkGroup(db.Model):
__tablename__ = 'workgroup'
id = db.Column(db.Integer, primary_key=True)
members_id = db.Column(db.Integer, db.ForeignKey('person.id'))
members = db.relationship('Person')
def __init__(self, *partners):
self.members = list(partners)
def include(self, newMember):
assert isinstance(newMember, Person)
self.members.append(newMember)
def group(self):
return set(self.members)
def __nonzero__(self):
return bool(self.members)
def __iter__(self):
return iter(self.members)
def clear(self):
self.members = []
def __str__(self): return str(self.members)
def __repr__(self): return self.__str__()
############################################################
def generateNewPairings():
all = Person.query.all()
if max([len(p.prevPairings) for p in all]) > len(all) - 2:
print "All Pairings Exhausted"
for p in all:
p.prevPairings = []
for p in all:
p.workGroup = None
def pairUp(everyone):
if len(everyone) % 2: # Odd number
oddOne = random.choice(everyone)
everyone.remove(oddOne)
pairUp(everyone) # Recurse with even number
random.choice(everyone).workGroup.include(oddOne)
return
for p in everyone: # Even number
p.findPartner(everyone)
pairUp(all)
for p in all: print p.show()
以下是完整的堆栈跟踪:
File "C:\Python27\lib\site-packages\flask\app.py", line 1701, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Python27\lib\site-packages\flask\app.py", line 1689, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "C:\Python27\lib\site-packages\flask\app.py", line 1687, in wsgi_app
response = self.full_dispatch_request()
File "C:\Python27\lib\site-packages\flask\app.py", line 1360, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Python27\lib\site-packages\flask\app.py", line 1358, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Python27\lib\site-packages\flask\app.py", line 1344, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\Bruce Eckel\Dropbox\AtomicScala\_AtomicScalaSeminarLocalServer\AtomicScalaSeminarSQLAlchemy.py", line 242, in generate_pairs
generateNewPairings()
File "C:\Users\Bruce Eckel\Dropbox\AtomicScala\_AtomicScalaSeminarLocalServer\AtomicScalaSeminarSQLAlchemy.py", line 120, in generateNewPairings
pairUp(all)
File "C:\Users\Bruce Eckel\Dropbox\AtomicScala\_AtomicScalaSeminarLocalServer\AtomicScalaSeminarSQLAlchemy.py", line 114, in pairUp
pairUp(everyone) # Recurse with even number
File "C:\Users\Bruce Eckel\Dropbox\AtomicScala\_AtomicScalaSeminarLocalServer\AtomicScalaSeminarSQLAlchemy.py", line 118, in pairUp
p.findPartner(everyone)
File "C:\Users\Bruce Eckel\Dropbox\AtomicScala\_AtomicScalaSeminarLocalServer\AtomicScalaSeminarSQLAlchemy.py", line 63, in findPartner
self.workGroup = WorkGroup(self, newPartner)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\attributes.py", line 238, in __set__
instance_dict(instance), value, None)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\attributes.py", line 736, in set
value = self.fire_replace_event(state, dict_, value, old, initiator)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\attributes.py", line 756, in fire_replace_event
value = fn(state, value, previous, initiator or self)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\unitofwork.py", line 89, in set_
sess._save_or_update_state(newvalue_state)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1389, in _save_or_update_state
halt_on=self._contains_state):
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1928, in cascade_iterator
parent_dict, visited_states, halt_on))
File "C:\Python27\lib\site-packages\sqlalchemy\orm\properties.py", line 929, in cascade_iterator
get_all_pending(state, dict_)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\attributes.py", line 693, in get_all_pending
ret = [(instance_state(current), current)]
AttributeError: 'list' object has no attribute '_sa_instance_state'
答案 0 :(得分:2)
我认为问题是您在db.relationship()
和Person
类中使用WorkGroup
。将其设置在其中一个中,并使用backref
关键字参数来定义另一侧的关系。
另一个问题是你把外键放在了错误的类中。由于您希望在Person
和WorkGroup
(一个工作组中有很多人)之间建立many-to-one关系,因此您需要在workgroup_id
类中定义Person
FK并删除来自members_id
的{{1}}(和members
)。
完成这些更改后,我遇到了WorkGroup
例外,很可能是由于CircularDependencyError
FK pointing to the same row。将prevPairings_id
添加到post_update=True
关系会修复该问题。
以下是您需要为代码工作所需的所有修复:
prevPairings