Changeset 144
- Timestamp:
- 07/05/07 10:48:39 (6 years ago)
- Location:
- elixir/trunk
- Files:
-
- 3 modified
-
CHANGES (modified) (1 diff)
-
elixir/relationships.py (modified) (13 diffs)
-
tests/test_movies.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
elixir/trunk/CHANGES
r143 r144 15 15 the method level and module level) anymore. Uses nosetest's module level 16 16 fixture. 17 - Fixed some buggy tests. 17 - Changed the order of relationship kwargs processing so that computed kwargs 18 can be overridden by kwargs manually passed to the statement. This should 19 only be used if you know what you are doing. 18 20 - Applied patch from Ants Aasma to make Elixir compatible with the 0.4 branch 19 21 of SQLAlchemy. 22 - Fixed some buggy tests. 20 23 - Fixed relationships to tables using a schema (Patch by Neil Blakey-Milner) 24 - Made inverse relationships use backrefs. This fixes the "bidirectional 25 coherency" problem some people had before doing a flush. (based on a patch 26 from Remi Jolin). 21 27 22 28 0.3.0 - 2007-03-27 -
elixir/trunk/elixir/relationships.py
r141 r144 192 192 from sqlalchemy import ForeignKeyConstraint, Column, \ 193 193 Table, and_ 194 from sqlalchemy.orm import relation 194 from sqlalchemy.orm import relation, backref 195 195 from elixir.statements import Statement 196 196 from elixir.fields import Field … … 216 216 217 217 self.property = None # sqlalchemy property 218 218 self.backref = None # sqlalchemy backref 219 219 220 #TODO: unused for now 220 221 self.args = args … … 240 241 properties to the involved entities. 241 242 ''' 243 kwargs = {} 244 if self.inverse: 245 # check if the inverse was already processed (and this has already defined 246 # a backref) 247 if self.inverse.backref: 248 kwargs['backref'] = self.inverse.backref 249 else: 250 kwargs = self.get_prop_kwargs() 251 252 # SQLAlchemy doesn't like when 'secondary' is both defined on 253 # the relation and the backref 254 kwargs.pop('secondary', None) 255 256 # define backref for use by the inverse 257 self.backref = backref(self.name, **kwargs) 258 return 259 260 kwargs.update(self.get_prop_kwargs()) 261 self.property = relation(self.target, **kwargs) 262 self.entity.mapper.add_property(self.name, self.property) 242 263 243 264 def setup(self): … … 249 270 return False 250 271 251 if self.property :272 if self.property or self.backref: 252 273 return True 253 274 … … 362 383 if source_desc.autoload: 363 384 #TODO: test if this works when colname is a list 385 364 386 if self.colname: 365 387 self.primaryjoin_clauses = \ … … 429 451 name=fk_name, 430 452 **self.constraint_kwargs)) 431 432 def create_properties(self):433 kwargs = self.kwargs453 454 def get_prop_kwargs(self): 455 kwargs = {'uselist': False} 434 456 435 457 if self.entity.table is self.target.table: … … 443 465 kwargs['primaryjoin'] = and_(*self.primaryjoin_clauses) 444 466 445 kwargs['uselist'] = False 446 447 self.property = relation(self.target, **kwargs) 448 self.entity.mapper.add_property(self.name, self.property) 467 kwargs.update(self.kwargs) 468 469 return kwargs 449 470 450 471 … … 470 491 self.inverse.setup() 471 492 472 def create_properties(self):473 kwargs = self.kwargs493 def get_prop_kwargs(self): 494 kwargs = {'uselist': self.uselist} 474 495 475 496 #TODO: for now, we don't break any test if we remove those 2 lines. … … 486 507 kwargs['primaryjoin'] = and_(*self.inverse.primaryjoin_clauses) 487 508 488 kwargs['uselist'] = self.uselist 489 490 self.property = relation(self.target, **kwargs) 491 self.entity.mapper.add_property(self.name, self.property) 509 kwargs.update(self.kwargs) 510 511 return kwargs 492 512 493 513 494 514 class HasMany(HasOne): 495 515 uselist = True 496 497 def create_properties(self): 498 if 'order_by' in self.kwargs: 499 self.kwargs['order_by'] = \ 516 517 def get_prop_kwargs(self): 518 kwargs = super(HasMany, self).get_prop_kwargs() 519 520 if 'order_by' in kwargs: 521 kwargs['order_by'] = \ 500 522 self.target._descriptor.translate_order_by( 501 self.kwargs['order_by'])502 503 super(HasMany, self).create_properties()523 kwargs['order_by']) 524 525 return kwargs 504 526 505 527 … … 653 675 self.entity.table) 654 676 655 def create_properties(self): 656 kwargs = self.kwargs 677 def get_prop_kwargs(self): 678 kwargs = {'secondary': self.secondary_table, 679 'uselist': self.uselist} 657 680 658 681 if self.target is self.entity: … … 660 683 kwargs['secondaryjoin'] = and_(*self.secondaryjoin_clauses) 661 684 685 kwargs.update(self.kwargs) 686 662 687 if 'order_by' in kwargs: 663 688 kwargs['order_by'] = \ 664 689 self.target._descriptor.translate_order_by(kwargs['order_by']) 665 690 666 self.property = relation(self.target, secondary=self.secondary_table, 667 uselist=self.uselist, **kwargs) 668 self.entity.mapper.add_property(self.name, self.property) 691 return kwargs 669 692 670 693 def is_inverse(self, other): … … 686 709 else: 687 710 cols2 = None 711 712 # Build a map of fk constraints pointing to the correct table. 713 # The map is indexed on the local col names. 688 714 constraint_map = {} 689 715 for constraint in local_table.constraints: 690 716 if isinstance(constraint, ForeignKeyConstraint): 691 use_constraint = False 717 718 use_constraint = True 692 719 fk_colnames = [] 720 721 # if all columns point to the correct table, we use the constraint 693 722 for fk in constraint.elements: 694 fk_colnames.append(fk.parent.name)695 723 if fk.references(target_table): 696 use_constraint = True 724 fk_colnames.append(fk.parent.name) 725 else: 726 use_constraint = False 697 727 if use_constraint: 698 728 fk_colnames.sort() … … 704 734 # know the other join is either not used (is None) or has an explicit 705 735 # match. 736 737 #TODO: rewrite this. Even with the comment, I don't even understand it myself. 706 738 for cols, constraint in constraint_map.iteritems(): 707 739 if cols == cols1 or (cols != cols2 and -
elixir/trunk/tests/test_movies.py
r125 r144 65 65 objectstore.clear() 66 66 67 def test_backref(self): 68 swars = Movie(title="Star Wars", year=1977) 69 glucas = Director(name="George Lucas") 70 swars.director = glucas 71 72 # does it work before a flush? 73 assert swars in glucas.movies 74 67 75 def test_bidirectional(self): 68 76 brunner = Movie(title="Blade Runner", year=1982)
