summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2006-10-16 00:37:53 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2006-10-16 00:37:53 +0000
commit819ef543b3ba04660609d5796b8bedc1f0e8a81f (patch)
treed59de8f658a6de2145cd0a150e26bfde833b0f50
parent0eb3b4ce93c5469e4c7634d7b1c51c6f3b933005 (diff)
downloadsqlalchemy-819ef543b3ba04660609d5796b8bedc1f0e8a81f.tar.gz
de-cruftification
-rw-r--r--CHANGES1
-rw-r--r--lib/sqlalchemy/orm/__init__.py4
-rw-r--r--lib/sqlalchemy/orm/mapper.py172
-rw-r--r--lib/sqlalchemy/orm/strategies.py6
-rw-r--r--test/orm/manytomany.py2
-rw-r--r--test/orm/mapper.py12
-rw-r--r--test/orm/unitofwork.py43
7 files changed, 134 insertions, 106 deletions
diff --git a/CHANGES b/CHANGES
index 5d3c1c34d..cbc4bc0ce 100644
--- a/CHANGES
+++ b/CHANGES
@@ -169,6 +169,7 @@
- added join_to and outerjoin_to transformative methods to SelectResults,
to build up join/outerjoin conditions based on property names. also
added select_from to explicitly set from_obj parameter.
+ - removed "is_primary" flag from mapper.
0.2.8
- cleanup on connection methods + documentation. custom DBAPI
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 7339d0fab..4ec3eb91e 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -18,7 +18,7 @@ import properties, strategies
from session import Session as create_session
__all__ = ['relation', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer',
- 'mapper', 'clear_mappers', 'sql', 'class_mapper', 'object_mapper', 'MapperExtension', 'Query',
+ 'mapper', 'clear_mappers', 'clear_mapper', 'sql', 'class_mapper', 'object_mapper', 'MapperExtension', 'Query',
'cascade_mappers', 'polymorphic_union', 'create_session', 'synonym', 'EXT_PASS'
]
@@ -57,7 +57,7 @@ def clear_mapper(m):
"""remove the given mapper from the storage of mappers. when a new mapper is
created for the previous mapper's class, it will be used as that classes'
new primary mapper."""
- del mapper_registry[m.hash_key]
+ del mapper_registry[m.class_key]
def eagerload(name):
"""return a MapperOption that will convert the property of the given name
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 6cd21626c..97c4bd58c 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -38,7 +38,6 @@ class Mapper(object):
local_table,
properties = None,
primary_key = None,
- is_primary = False,
non_primary = False,
inherits = None,
inherit_condition = None,
@@ -49,13 +48,79 @@ class Mapper(object):
always_refresh = False,
version_id_col = None,
polymorphic_on=None,
- polymorphic_map=None,
+ _polymorphic_map=None,
polymorphic_identity=None,
concrete=False,
select_table=None,
allow_null_pks=False,
batch=True):
-
+ """construct a new mapper.
+
+ All arguments may be sent to the sqlalchemy.orm.mapper() function where they are
+ passed through to here.
+
+ class_ - the class to be mapped.
+
+ local_table - the table to which the class is mapped, or None if this mapper inherits
+ from another mapper using concrete table inheritance.
+
+ properties - a dictionary mapping the string names of object attributes to MapperProperty
+ instances, which define the persistence behavior of that attribute. Note that the columns in the
+ mapped table are automatically converted into ColumnProperty instances based on the "key"
+ property of each Column (although they can be overridden using this dictionary).
+
+ primary_key - a list of Column objects which define the "primary key" to be used against this mapper's
+ selectable unit. This is normally simply the primary key of the "local_table", but can be overridden here.
+
+ non_primary - construct a Mapper that will define only the selection of instances, not their persistence.
+
+ inherits - another Mapper for which this Mapper will have an inheritance relationship with.
+
+ inherit_condition - for joined table inheritance, a SQL expression (constructed ClauseElement) which
+ will define how the two tables are joined; defaults to a natural join between the two tables.
+
+ extension - a MapperExtension instance or list of MapperExtension instances which will be applied to
+ all operations by this Mapper.
+
+ order_by - a single Column or list of Columns for which selection operations should use as the default
+ ordering for entities. Defaults to the OID/ROWID of the table if any, or the first primary key column of the table.
+
+ allow_column_override - if True, allows association relationships to be set up which override the usage of
+ a column that is on the table (based on key/attribute name).
+
+ entity_name - a name to be associated with the class, to allow alternate mappings for a single class.
+
+ always_refresh - if True, all query operations for this mapped class will overwrite all data
+ within object instances that already exist within the session, erasing any in-memory changes with whatever
+ information was loaded from the database.
+
+ version_id_col - a Column which must have an integer type that will be used to keep a running "version id" of
+ mapped entities in the database. this is used during save operations to insure that no other thread or process
+ has updated the instance during the lifetime of the entity, else a ConcurrentModificationError exception is thrown.
+
+ polymorphic_on - used with mappers in an inheritance relationship, a Column which will identify the class/mapper
+ combination to be used with a particular row. requires the polymorphic_identity value to be set for all mappers
+ in the inheritance hierarchy.
+
+ _polymorphic_map - used internally to propigate the full map of polymorphic identifiers to surrogate mappers.
+
+ polymorphic_identity - a value which will be stored in the Column denoted by polymorphic_on, corresponding to the
+ "class identity" of this mapper.
+
+ concrete - if True, indicates this mapper should use concrete table inheritance with its parent mapper.
+
+ select_table - a Table or (more commonly) Selectable which will be used to select instances of this mapper's class.
+ usually used to provide polymorphic loading among several classes in an inheritance hierarchy.
+
+ allow_null_pks - indicates that composite primary keys where one or more (but not all) columns contain NULL is a valid
+ primary key. Primary keys which contain NULL values usually indicate that a result row does not contain an entity
+ and should be skipped.
+
+ batch - indicates that save operations of multiple entities can be batched together for efficiency.
+ setting to False indicates that an instance will be fully saved before saving the next instance, which
+ includes inserting/updating all table rows corresponding to the entity as well as calling all MapperExtension
+ methods corresponding to the save operation.
+ """
if not issubclass(class_, object):
raise exceptions.ArgumentError("Class '%s' is not a new-style class" % class_.__name__)
@@ -71,7 +136,6 @@ class Mapper(object):
self.class_ = class_
self.entity_name = entity_name
self.class_key = ClassKey(class_, entity_name)
- self.is_primary = is_primary
self.primary_key = primary_key
self.non_primary = non_primary
self.order_by = order_by
@@ -100,10 +164,10 @@ class Mapper(object):
# a dictionary of 'polymorphic identity' names, associating those names with
# Mappers that will be used to construct object instances upon a select operation.
- if polymorphic_map is None:
+ if _polymorphic_map is None:
self.polymorphic_map = {}
else:
- self.polymorphic_map = polymorphic_map
+ self.polymorphic_map = _polymorphic_map
class LOrderedProp(util.OrderedProperties):
"""this extends OrderedProperties to trigger a compile() before the
@@ -434,7 +498,7 @@ class Mapper(object):
props[key] = self.select_table.corresponding_column(prop)
elif (isinstance(prop, list) and sql.is_column(prop[0])):
props[key] = [self.select_table.corresponding_column(c) for c in prop]
- self.__surrogate_mapper = Mapper(self.class_, self.select_table, non_primary=True, properties=props, polymorphic_map=self.polymorphic_map, polymorphic_on=self.select_table.corresponding_column(self.polymorphic_on))
+ self.__surrogate_mapper = Mapper(self.class_, self.select_table, non_primary=True, properties=props, _polymorphic_map=self.polymorphic_map, polymorphic_on=self.select_table.corresponding_column(self.polymorphic_on))
def _compile_class(self):
"""if this mapper is to be a primary mapper (i.e. the non_primary flag is not set),
@@ -444,8 +508,8 @@ class Mapper(object):
if self.non_primary:
return
- if not self.non_primary and (mapper_registry.has_key(self.class_key) and not self.is_primary):
- raise exceptions.ArgumentError("Class '%s' already has a primary mapper defined. Use is_primary=True to assign a new primary mapper to the class, or use non_primary=True to create a non primary Mapper" % self.class_)
+ if not self.non_primary and (mapper_registry.has_key(self.class_key)):
+ raise exceptions.ArgumentError("Class '%s' already has a primary mapper defined with entity name '%s'. Use non_primary=True to create a non primary Mapper, or to create a new primary mapper, remove this mapper first via sqlalchemy.orm.clear_mapper(mapper), or preferably sqlalchemy.orm.clear_mappers() to clear all mappers." % (self.class_, self.entity_name))
sessionlib.attribute_manager.reset_class_managed(self.class_)
@@ -532,9 +596,6 @@ class Mapper(object):
yield x
return iterate(m)
- def accept_mapper_option(self, option):
- option.process_mapper(self)
-
def add_properties(self, dict_of_properties):
"""adds the given dictionary of properties to this mapper, using add_property."""
for key, value in dict_of_properties.iteritems():
@@ -986,13 +1047,21 @@ class Mapper(object):
return False
def register_dependencies(self, uowcommit, *args, **kwargs):
- """called by an instance of unitofwork.UOWTransaction to register
- which mappers are dependent on which, as well as DependencyProcessor
- objects which will process lists of objects in between saves and deletes."""
+ """register DependencyProcessor instances with a unitofwork.UOWTransaction.
+
+ this calls register_dependencies on all attached MapperProperty instances."""
for prop in self.__props.values():
prop.register_dependencies(uowcommit, *args, **kwargs)
def cascade_iterator(self, type, object, recursive=None):
+ """iterate each element in an object graph, for all relations taht meet the given cascade rule.
+
+ type - the name of the cascade rule (i.e. save-update, delete, etc.)
+
+ object - the lead object instance. child items will be processed per the relations
+ defined for this object's mapper.
+
+ recursive - used by the function for internal context during recursive calls, leave as None."""
if recursive is None:
recursive=util.Set()
for prop in self.__props.values():
@@ -1000,6 +1069,16 @@ class Mapper(object):
yield c
def cascade_callable(self, type, object, callable_, recursive=None):
+ """execute a callable for each element in an object graph, for all relations that meet the given cascade rule.
+
+ type - the name of the cascade rule (i.e. save-update, delete, etc.)
+
+ object - the lead object instance. child items will be processed per the relations
+ defined for this object's mapper.
+
+ callable_ - the callable function.
+
+ recursive - used by the function for internal context during recursive calls, leave as None."""
if recursive is None:
recursive=util.Set()
for prop in self.__props.values():
@@ -1009,6 +1088,9 @@ class Mapper(object):
return sessionlib.get_row_key(row, self.class_, self.pks_by_table[self.mapped_table], self.entity_name)
def get_select_mapper(self):
+ """return the mapper used for issuing selects.
+
+ this mapper is the same mapper as 'self' unless the select_table argument was specified for this mapper."""
return self.__surrogate_mapper or self
def _instance(self, context, row, result = None):
@@ -1112,66 +1194,6 @@ class Mapper(object):
for prop in self.__props.values():
prop.execute(selectcontext, instance, row, identitykey, isnew)
- # deprecated query methods. Query is constructed from Session, and the rest
- # of these methods are called off of Query now.
- def query(self, session=None):
- """deprecated. use Query instead."""
- if session is not None:
- return querylib.Query(self, session=session)
-
- try:
- if self._query.mapper is not self:
- self._query = querylib.Query(self)
- return self._query
- except AttributeError:
- self._query = querylib.Query(self)
- return self._query
- def using(self, session):
- """deprecated. use Query instead."""
- return querylib.Query(self, session=session)
- def get(self, ident, **kwargs):
- """deprecated. use Query instead."""
- return self.query().get(ident, **kwargs)
- def _get(self, key, ident=None, reload=False):
- """deprecated. use Query instead."""
- return self.query()._get(key, ident=ident, reload=reload)
- def get_by(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().get_by(*args, **params)
- def select_by(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().select_by(*args, **params)
- def selectfirst_by(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().selectfirst_by(*args, **params)
- def selectone_by(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().selectone_by(*args, **params)
- def count_by(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().count_by(*args, **params)
- def selectfirst(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().selectfirst(*args, **params)
- def selectone(self, *args, **params):
- """deprecated. use Query instead."""
- return self.query().selectone(*args, **params)
- def select(self, arg=None, **kwargs):
- """deprecated. use Query instead."""
- return self.query().select(arg=arg, **kwargs)
- def select_whereclause(self, whereclause=None, params=None, **kwargs):
- """deprecated. use Query instead."""
- return self.query().select_whereclause(whereclause=whereclause, params=params, **kwargs)
- def count(self, whereclause=None, params=None, **kwargs):
- """deprecated. use Query instead."""
- return self.query().count(whereclause=whereclause, params=params, **kwargs)
- def select_statement(self, statement, **params):
- """deprecated. use Query instead."""
- return self.query().select_statement(statement, **params)
- def select_text(self, text, **params):
- """deprecated. use Query instead."""
- return self.query().select_text(text, **params)
-
Mapper.logger = logging.class_logger(Mapper)
class SelectionContext(OperationContext):
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 9b2522640..991ff66cc 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -5,7 +5,7 @@
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from sqlalchemy import sql, schema, util, attributes, exceptions, sql_util, logging
-import mapper
+import mapper, query
from interfaces import *
import session as sessionlib
import util as mapperutil
@@ -153,7 +153,7 @@ class LazyLoader(AbstractRelationLoader):
(self.lazywhere, self.lazybinds, self.lazyreverse) = self._create_lazy_clause(self.parent.unjoined_table, self.primaryjoin, self.secondaryjoin, self.foreignkey)
# determine if our "lazywhere" clause is the same as the mapper's
# get() clause. then we can just use mapper.get()
- self.use_get = not self.uselist and self.mapper.query()._get_clause.compare(self.lazywhere)
+ self.use_get = not self.uselist and query.Query(self.mapper)._get_clause.compare(self.lazywhere)
def init_class_attribute(self):
self._register_attribute(self.parent.class_, callable_=lambda i: self.setup_loader(i))
@@ -200,7 +200,7 @@ class LazyLoader(AbstractRelationLoader):
for primary_key in self.mapper.pks_by_table[self.mapper.mapped_table]:
bind = self.lazyreverse[primary_key]
ident.append(params[bind.key])
- return self.mapper.using(session).get(ident)
+ return session.query(self.mapper).get(ident)
elif self.order_by is not False:
order_by = self.order_by
elif self.secondary is not None and self.secondary.default_order_by() is not None:
diff --git a/test/orm/manytomany.py b/test/orm/manytomany.py
index dc343cb95..1768ecf6c 100644
--- a/test/orm/manytomany.py
+++ b/test/orm/manytomany.py
@@ -309,7 +309,7 @@ class M2MTest3(testbase.AssertMixin):
}
)
- o1 = C.get(1)
+ o1 = create_session().query(C).get(1)
if __name__ == "__main__":
diff --git a/test/orm/mapper.py b/test/orm/mapper.py
index fad13b5c0..4a816c16c 100644
--- a/test/orm/mapper.py
+++ b/test/orm/mapper.py
@@ -363,7 +363,7 @@ class MapperTest(MapperSuperTest):
# first test straight eager load, 1 statement
def go():
- l = usermapper.query(sess).select()
+ l = sess.query(usermapper).select()
self.assert_result(l, User, *user_address_result)
self.assert_sql_count(db, go, 1)
@@ -401,9 +401,11 @@ class MapperTest(MapperSuperTest):
# first test straight eager load, 1 statement
def go():
- l = usermapper.query(sess).select()
+ l = sess.query(usermapper).select()
self.assert_result(l, User, *user_all_result)
self.assert_sql_count(db, go, 1)
+
+ sess.clear()
# then select just from users. run it into instances.
# then assert the data, which will launch 6 more lazy loads
@@ -749,7 +751,8 @@ class LazyTest(MapperSuperTest):
self.assert_result(l, User, *user_all_result)
sess.clear()
- m = mapper(Item, orderitems, is_primary=True, properties = dict(
+ clear_mappers()
+ m = mapper(Item, orderitems, properties = dict(
keywords = relation(mapper(Keyword, keywords), itemkeywords, lazy = True),
))
@@ -888,7 +891,8 @@ class EagerTest(MapperSuperTest):
l = q.select(s.c.u2_user_id==User.c.user_id, distinct=True)
self.assert_result(l, User, *user_all_result)
sess.clear()
- m = mapper(Item, orderitems, is_primary=True, properties = dict(
+ clear_mappers()
+ m = mapper(Item, orderitems, properties = dict(
keywords = relation(mapper(Keyword, keywords), itemkeywords, lazy = False, order_by=[keywords.c.keyword_id]),
))
q = sess.query(m)
diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py
index 6cf2b4b49..debf63ce3 100644
--- a/test/orm/unitofwork.py
+++ b/test/orm/unitofwork.py
@@ -112,7 +112,7 @@ class VersioningTest(UnitOfWorkTest):
f1.value='f1rev2'
s.flush()
s2 = create_session()
- f1_s = Foo.mapper.using(s2).get(f1.id)
+ f1_s = s2.query(Foo).get(f1.id)
f1_s.value='f1rev3'
s2.flush()
@@ -468,8 +468,8 @@ class PrivateAttrTest(UnitOfWorkTest):
ctx.current.flush()
ctx.current.clear()
sess = ctx.current
- a1 = A.mapper.get(a1.a_id)
- a2 = A.mapper.get(a2.a_id)
+ a1 = Query(A).get(a1.a_id)
+ a2 = Query(A).get(a2.a_id)
assert a1.bs[0].a is a1
b = a1.bs[0]
b.a = a2
@@ -522,7 +522,7 @@ class DefaultTest(UnitOfWorkTest):
self.assert_(h2.foober == h3.foober == h4.foober == 'im foober')
self.assert_(h5.foober=='im the new foober')
ctx.current.clear()
- l = Hoho.mapper.select()
+ l = Query(Hoho).select()
(h1, h2, h3, h4, h5) = l
self.assert_(h1.hoho==self.althohoval)
self.assert_(h3.hoho==self.althohoval)
@@ -593,7 +593,7 @@ class SaveTest(UnitOfWorkTest):
ctx.current.flush()
# assert the first one retreives the same from the identity map
- nu = m.get(u.user_id)
+ nu = ctx.current.get(m, u.user_id)
self.echo( "U: " + repr(u) + "NU: " + repr(nu))
self.assert_(u is nu)
@@ -601,7 +601,7 @@ class SaveTest(UnitOfWorkTest):
ctx.current.clear()
# check it again, identity should be different but ids the same
- nu = m.get(u.user_id)
+ nu = ctx.current.get(m, u.user_id)
self.assert_(u is not nu and u.user_id == nu.user_id and nu.user_name == 'savetester')
# change first users name and save
@@ -612,7 +612,7 @@ class SaveTest(UnitOfWorkTest):
# select both
#ctx.current.clear()
- userlist = m.select(users.c.user_id.in_(u.user_id, u2.user_id), order_by=[users.c.user_name])
+ userlist = Query(m).select(users.c.user_id.in_(u.user_id, u2.user_id), order_by=[users.c.user_name])
print repr(u.user_id), repr(userlist[0].user_id), repr(userlist[0].user_name)
self.assert_(u.user_id == userlist[0].user_id and userlist[0].user_name == 'modifiedname')
self.assert_(u2.user_id == userlist[1].user_id and userlist[1].user_name == 'savetester2')
@@ -631,7 +631,7 @@ class SaveTest(UnitOfWorkTest):
u.addresses.append(Address())
ctx.current.flush()
ctx.current.clear()
- ulist = m1.select()
+ ulist = ctx.current.query(m1).select()
u1 = ulist[0]
u1.user_name = 'newname'
ctx.current.flush()
@@ -653,7 +653,7 @@ class SaveTest(UnitOfWorkTest):
au = AddressUser()
ctx.current.flush()
ctx.current.clear()
- l = AddressUser.mapper.selectone()
+ l = ctx.current.query(AddressUser).selectone()
self.assert_(l.user_id == au.user_id and l.address_id == au.address_id)
def testdeferred(self):
@@ -686,7 +686,7 @@ class SaveTest(UnitOfWorkTest):
ctx.current.clear()
- u = m.get(id)
+ u = ctx.current.get(User, id)
assert u.user_name == 'multitester'
usertable = users.select(users.c.user_id.in_(u.foo_id)).execute().fetchall()
@@ -704,7 +704,7 @@ class SaveTest(UnitOfWorkTest):
self.assertEqual(addresstable[0].values(), [u.address_id, u.foo_id, 'lala@hey.com'])
ctx.current.clear()
- u = m.get(id)
+ u = ctx.current.get(User, id)
assert u.user_name == 'imnew'
def testhistoryget(self):
@@ -815,7 +815,7 @@ class SaveTest(UnitOfWorkTest):
ctx.current.delete(u1)
ctx.current.flush()
ctx.current.clear()
- u2 = m.get(u2.user_id)
+ u2 = ctx.current.get(User, u2.user_id)
assert len(u2.addresses) == 1
def testdelete(self):
@@ -942,14 +942,15 @@ class SaveTest(UnitOfWorkTest):
# mapper with just users table
assign_mapper(User, users)
- User.mapper.select()
+ ctx.current.query(User).select()
oldmapper = User.mapper
# now a mapper with the users table plus a relation to the addresses
- assign_mapper(User, users, is_primary=True, properties = dict(
+ clear_mapper(User.mapper)
+ assign_mapper(User, users, properties = dict(
addresses = relation(mapper(Address, addresses), lazy = False)
))
self.assert_(oldmapper is not User.mapper)
- u = User.mapper.select()
+ u = ctx.current.query(User).select()
u[0].addresses.append(Address())
u[0].addresses[0].email_address='hi'
@@ -1056,7 +1057,7 @@ class SaveTest(UnitOfWorkTest):
item.item_name = elem['item_name']
item.keywords = []
if len(elem['keywords'][1]):
- klist = keywordmapper.select(keywords.c.name.in_(*[e['name'] for e in elem['keywords'][1]]))
+ klist = ctx.current.query(keywordmapper).select(keywords.c.name.in_(*[e['name'] for e in elem['keywords'][1]]))
else:
klist = []
khash = {}
@@ -1072,7 +1073,7 @@ class SaveTest(UnitOfWorkTest):
ctx.current.flush()
- l = m.select(items.c.item_name.in_(*[e['item_name'] for e in data[1:]]), order_by=[items.c.item_name, keywords.c.name])
+ l = ctx.current.query(m).select(items.c.item_name.in_(*[e['item_name'] for e in data[1:]]), order_by=[items.c.item_name, keywords.c.name])
self.assert_result(l, *data)
objects[4].item_name = 'item4updated'
@@ -1228,7 +1229,7 @@ class SaveTest(UnitOfWorkTest):
item.keywords = []
for kname in [e['keyword'][1]['name'] for e in elem['keywords'][1]]:
try:
- k = keywordmapper.select(keywords.c.name == kname)[0]
+ k = Query(keywordmapper).select(keywords.c.name == kname)[0]
except IndexError:
k = Keyword()
k.name= kname
@@ -1238,15 +1239,15 @@ class SaveTest(UnitOfWorkTest):
ctx.current.flush()
ctx.current.clear()
- l = m.select(items.c.item_name.in_(*[e['item_name'] for e in data[1:]]), order_by=[items.c.item_name, keywords.c.name])
+ l = Query(m).select(items.c.item_name.in_(*[e['item_name'] for e in data[1:]]), order_by=[items.c.item_name, keywords.c.name])
self.assert_result(l, *data)
def testbidirectional(self):
- m1 = mapper(User, users, is_primary=True)
+ m1 = mapper(User, users)
m2 = mapper(Address, addresses, properties = dict(
user = relation(m1, lazy = False, backref='addresses')
- ), is_primary=True)
+ ))
u = User()