# related mappers. its dependency processor then populates the
# association table.
- if self.is_backref:
- # if we are the "backref" half of a two-way backref
- # relationship, let the other mapper handle inserting the rows
- return
stub = MapperStub(self.parent, self.mapper, self.key)
uowcommit.register_dependency(self.parent, stub)
uowcommit.register_dependency(self.mapper, stub)
uowcommit.register_processor(stub, self, self.parent)
def process_dependencies(self, task, deplist, uowcommit, delete = False):
- #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
+ #print self.mapper.mapped_table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction)
connection = uowcommit.transaction.connection(self.mapper)
secondary_delete = []
secondary_insert = []
+
+ if hasattr(self.prop, 'reverse_property'):
+ reverse_dep = getattr(self.prop.reverse_property, '_dependency_processor', None)
+ else:
+ reverse_dep = None
+
if delete:
for obj in deplist:
childlist = self.get_object_dependencies(obj, uowcommit, passive=self.passive_deletes)
if childlist is not None:
for child in childlist.deleted_items() + childlist.unchanged_items():
+ if reverse_dep and (reverse_dep, "manytomany", child, obj) in uowcommit.attributes:
+ continue
associationrow = {}
self._synchronize(obj, child, associationrow, False, uowcommit)
secondary_delete.append(associationrow)
+ uowcommit.attributes[(self, "manytomany", obj, child)] = True
else:
for obj in deplist:
childlist = self.get_object_dependencies(obj, uowcommit)
if childlist is None: continue
for child in childlist.added_items():
+ if reverse_dep and (reverse_dep, "manytomany", child, obj) in uowcommit.attributes:
+ continue
associationrow = {}
self._synchronize(obj, child, associationrow, False, uowcommit)
+ uowcommit.attributes[(self, "manytomany", obj, child)] = True
secondary_insert.append(associationrow)
for child in childlist.deleted_items():
+ if reverse_dep and (reverse_dep, "manytomany", child, obj) in uowcommit.attributes:
+ continue
associationrow = {}
self._synchronize(obj, child, associationrow, False, uowcommit)
+ uowcommit.attributes[(self, "manytomany", obj, child)] = True
secondary_delete.append(associationrow)
if len(secondary_delete):
secondary_delete.sort()
self.tasks = {}
self.logger = logging.instance_logger(self)
self.echo = uow.echo
-
+ self.attributes = {}
+
echo = logging.echo_property()
def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, post_update_cols=None, **kwargs):
targettask = self.get_task_by_mapper(mapperfrom)
up = UOWDependencyProcessor(processor, targettask)
task.dependencies.add(up)
-
+
def execute(self):
# ensure that we have a UOWTask for every mapper that will be involved
# in the topological sort
self.assert_(len(s.courses) == 3)
del s.courses[1]
self.assert_(len(s.courses) == 2)
+
+ def test_delete(self):
+ """test that many-to-many table gets cleared out with deletion from the backref side"""
+ 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().scalar() == 0
class M2MTest3(testbase.ORMTest):
def define_tables(self, metadata):