- changed milestone to 0.3.0
many-to-many relations dont delete/do anything properly if the is_backref flag is on
Issue #249
resolved
foo_baa = Table('foo_baa', activemapper.metadata,
Column('foo_id', Integer, ForeignKey('foo.id'), primary_key=True),
Column('baa_id', Integer, ForeignKey('baa.id'), primary_key=True))
class Foo(ActiveMapper):
class mapping:
name = column(String)
baas = many_to_many('Baa', foo_baa, backref='foos')
def __str__(self):
return "<Foo %r>" % self.name
class Baa(ActiveMapper):
class mapping:
name = column(String)
def __str__(self):
return "<Baa %r>" % self.name
>>> for x in ('First', 'Second'):
... Foo(name='Foo%s' % x)
... Baa(name='Baa%s' % x)
>>> objectstore.flush()
[00:18:37,643](2006-07-21) [engine](engine): BEGIN
[00:18:37,741](2006-07-21) [engine](engine): INSERT INTO baa (name) VALUES (%s)
[00:18:37,743](2006-07-21) [engine](engine): ['BaaFirst']('BaaFirst')
[00:18:37,790](2006-07-21) [engine](engine): INSERT INTO baa (name) VALUES (%s)
[00:18:37,807](2006-07-21) [engine](engine): ['BaaSecond']('BaaSecond')
[00:18:37,839](2006-07-21) [engine](engine): INSERT INTO foo (name) VALUES (%s)
[00:18:37,840](2006-07-21) [engine](engine): ['FooFirst']('FooFirst')
[00:18:37,872](2006-07-21) [engine](engine): INSERT INTO foo (name) VALUES (%s)
[00:18:37,874](2006-07-21) [engine](engine): ['FooSecond']('FooSecond')
[00:18:37,902](2006-07-21) [engine](engine): COMMIT
>>> # get Foo object with id 1 and add relation to <Baa 'BaaFirst'> and flush
>>> obj = Foo.get(1)
>>> print obj.baas
[obj.baas.append(Baa.get(1))
>>> obj.flush()
[2006-07-21 00:18:38,027](]
>>>) [engine](engine): BEGIN
[00:18:38,031](2006-07-21) [engine](engine): INSERT INTO foo_baa (foo_id, baa_id) VALUES
(%s, %s)
[00:18:38,034](2006-07-21) [engine](engine): [1L](1L,)
[00:18:38,061](2006-07-21) [engine](engine): COMMIT
>>> print obj.baas
[object at 0x55de50>](<__main__.Baa)
>>> # get Baa object with id 1 (<Baa 'BaaFirst'>) and add relation to <Foo 'FooSecond'>
>>> # from Baa and flush
>>> obj = Baa.get(1)
>>> print obj.foos
[object at 0x5220b0>](<__main__.Foo)
>>> obj.foos.append(Foo.get(2))
>>> obj.flush()
[00:18:38,123](2006-07-21) [engine](engine): BEGIN
[00:18:38,127](2006-07-21) [engine](engine): COMMIT
In my opinion obj.flush() should also commit changes between it's ManyToMany-relations. Now it works only from "active" side of relation (Foo in this example). objectstore.flush() would obviously do the trick, but that is something that id wouldn't like to do at my Web Framework's controller. obj.save() or obj.flush() would be much more logical.
Comments (6)
-
repo owner -
repo owner - changed milestone to 0.4.0
-
repo owner - changed title to many-to-many relations dont delete/do anything properly if the is_backref flag is on
- marked as blocker
- changed milestone to 0.3.6
-
repo owner another failing test:
from sqlalchemy import * metadata = BoundMetaData('sqlite://') studentTbl = Table('student', metadata, Column('name', String(20), primary_key=True)) courseTbl = Table('course', metadata, Column('name', String(20), primary_key=True)) enrolTbl = Table('enrol', metadata, Column('student_id', String(20), ForeignKey('student.name'),primary_key=True), Column('course_id', String(20), ForeignKey('course.name'), primary_key=True)) metadata.create_all() class Student(object): def __init__(self, name=''): self.name = name class Course(object): def __init__(self, name=''): self.name = name Student.mapper = mapper(Student, studentTbl) Course.mapper = mapper(Course, courseTbl, properties = { 'students': relation(Student.mapper, enrolTbl, lazy=True, backref='courses') }) sess = create_session() s1 = Student('Student1') c1 = Course('Course1') c2 = Course('Course2') c3 = Course('Course3') s1.courses.append(c1) s1.courses.append(c2) c3.students.append(s1) sess.save(s1) sess.flush() sess.delete(s1) sess.flush() assert enrolTbl.count().execute() == 0
-
repo owner - changed status to resolved
-
repo owner - removed milestone
Removing milestone: 0.3.6 (automated comment)
- Log in to comment
in case you feel like playing with this, line 248 of sqlalchemy/orm/dependency.py is exactly where this happens :
the solution involves the two corresponding DependencyProcessors being aware of each other, and either coexisting within the UOWTransaction and somehow insuring that only one of them does the many-to-many update of the rows, or checking if the other one is not present and then placing itself in the UOWTransaction.