4

我有一个烧瓶应用程序,我在其中创建了一堆相互关联的类:

用户课程讲义队列资产

所以我正在尝试做一个新的讲座和笔记,我为每一件事定义了一个方法。

创建注释

def createPad(user,course,lecture):
    lecture.queues.first().users.append(user)
    # make new etherpad for user to wait in
    newNote = Note(dt) # init also creates a new pad at /p/groupID$noteID
    db.session.add(newNote)
    #db.session.commit()

    # add note to user, course, and lecture
    user.notes.append(newNote)
    course.notes.append(newNote)
    lecture.notes.append(newNote)
    db.session.commit()

return newNote

创建讲座

def createLecture(user, course):
    # create new lecture
    now = datetime.now()
    dt = now.strftime("%Y-%m-%d-%H-%M")
    newLecture = Lecture(dt)
    db.session.add(newLecture)

    # add lecture to course, add new queue to lecture, add user to queue, add new user to lecture
    course.lectures.append(newLecture)
    newQueue = MatchQueue('neutral')
    db.session.add(newQueue)
    newLecture.users.append(user)


    # hook up the new queue to the user, lecture
    newQueue.users.append(user)
    newQueue.lecture = newLecture
    # put new lecture in correct course
    db.session.commit()

    newLecture.groupID = pad.createGroupIfNotExistsFor(newLecture.course.name+dt)['groupID']

    db.session.commit()
    return newLecture

这都是从一些控制器逻辑调用的

newlec = createLecture(user, courseobj)

# make new pad
newNote = createPad(user,courseobj,newlec)

# make lecture live
newLecture.live = True
db.session.commit()

redirect(somewhere)

这最终会引发此错误:

ObjectDereferencedError:无法为属性“Queue.users”发出更改事件 - 类型的父对象已被垃圾收集。

在. lecture.queues.first().users.append(user)_createPad

我不知道这意味着什么。我想我在这里缺乏一些关于 sqlalchemy 的基本知识(我是 sqlalchemy 菜鸟)。这是怎么回事?

4

2 回答 2

12
lecture.queues.first().users.append(user)

它的意思是:

first() 方法访问数据库并生成一个对象,我没有关注您的映射,但我猜它是一个 Queue 对象。

然后,您访问队列上的“用户”集合。

此时,Python 本身会垃圾收集Queue - 一旦返回“用户”,它就不会在任何地方引用。这就是引用计数垃圾回收的工作原理。

然后您尝试将“用户”附加到“用户”。SQLAlchemy 必须跟踪对所有映射属性的更改,如果您说Queue.name = "some name",SQLAlchemy 需要将其注册到父Queue对象,以便它知道刷新它。如果你说Queue.users.append(someuser),同样的想法,它需要向父级注册更改事件。

SQLAlchemy 不能这样做,因为它Queue已经消失了。因此,该消息被提出。SQLAlchemy 在这里对父级有一个弱引用,因此它确切地知道发生了什么(我们无法阻止它,因为当我们在他们的对象模型中创建不必要的引用循环时人们会非常沮丧)。

该解决方案非常简单且易于阅读,即将查询结果分配给变量:

queue = lecture.queues.first()
queue.users.append(user)
于 2013-01-16T14:32:21.120 回答
0

我做了一堆重构,在实例化的时候放入了一些对象对应的对象,这让事情变得整洁了很多。不知何故,问题消失了。

我做的不同的一件事是在我的多对多关系中,我将 backref 更改为 db.backref():

courses = db.relationship('Course', secondary=courseTable, backref=db.backref('users', lazy='dynamic'))
lectures = db.relationship('Lecture', secondary=lectureTable, backref=db.backref('users', lazy='dynamic'))
notes = db.relationship('Note', secondary=noteTable, backref=db.backref('users', lazy='dynamic'))
queues = db.relationship('Queue', secondary=queueTable, backref=db.backref('users', lazy='dynamic'))
于 2013-01-16T04:20:50.150 回答