Changeset 458 for elixir/trunk/elixir

Show
Ignore:
Timestamp:
09/17/09 13:54:19 (3 years ago)
Author:
ged
Message:

- Changed the pattern used by default to generate column names for (all)

ManyToMany relationships so that the meaning of bidirectional
self-referential relationships does not depend on the order of declaration
of each side (closes #69). See upgrade notes for details.

- Made M2MCOL_NAMEFORMAT accept a callable, so that more complex naming

generation can be used if so desired.

Location:
elixir/trunk/elixir
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • elixir/trunk/elixir/options.py

    r437 r458  
    184184# format constants 
    185185FKCOL_NAMEFORMAT = "%(relname)s_%(key)s" 
    186 M2MCOL_NAMEFORMAT = "%(tablename)s_%(key)s" 
     186OLD_M2MCOL_NAMEFORMAT = "%(tablename)s_%(key)s%(numifself)s" 
     187NEW_M2MCOL_NAMEFORMAT = "%(relname)s_%(key)s" 
     188M2MCOL_NAMEFORMAT = NEW_M2MCOL_NAMEFORMAT 
    187189CONSTRAINT_NAMEFORMAT = "%(tablename)s_%(colnames)s_fk" 
    188190MULTIINHERITANCECOL_NAMEFORMAT = "%(entity)s_%(key)s" 
     
    197199 
    198200# debugging/migration help 
    199 CHECK_TABLENAME_CHANGES = False 
     201MIGRATION_TO_07_AID = False 
    200202 
    201203# 
  • elixir/trunk/elixir/relationships.py

    r455 r458  
    417417__doc_all__ = [] 
    418418 
     419 
    419420class Relationship(Property): 
    420421    ''' 
     
    862863                "all ManyToMany tables", DeprecationWarning, stacklevel=3) 
    863864        self.column_format = column_format or options.M2MCOL_NAMEFORMAT 
     865        if not callable(self.column_format): 
     866            # we need to store the format in a variable so that the 
     867            # closure of the lambda is correct 
     868            format = self.column_format 
     869            self.column_format = lambda data: format % data 
     870        if options.MIGRATION_TO_07_AID: 
     871            self.column_format = \ 
     872                migration_aid_column_formatter(self.column_format) 
    864873 
    865874        self.filter = filter 
     
    938947            # whether this relation or its inverse is setup first). 
    939948            if self.inverse and source_part < target_part: 
    940                 #TODO: if self-relf, only include source_part 
     949                #XXX: use a different scheme for selfref (to not include the 
     950                #     table name twice)? 
    941951                tablename = "%s__%s" % (target_part, source_part) 
    942                 if options.CHECK_TABLENAME_CHANGES and \ 
     952                if options.MIGRATION_TO_07_AID and \ 
    943953                   e1_desc.tablename >= e2_desc.tablename: 
    944954                    oldname = "%s__%s" % (source_part, target_part) 
    945  
    946                     raise Exception( 
     955                    warnings.warn( 
    947956                        "The generated table name for the '%s' relationship " 
    948957                        "on the '%s' entity changed from '%s' (the name " 
     
    9961005                    assert len(colnames) == len(desc.primary_keys) 
    9971006                else: 
     1007                    data = {# relationship info 
     1008                            'relname': rel and rel.name or 'inverse', 
     1009                            'selfref': e1_desc is e2_desc, 
     1010                            'num': num, 
     1011                            'numifself': e1_desc is e2_desc and str(num + 1) 
     1012                                                            or '', 
     1013                            # target info 
     1014                            'target': desc.entity, 
     1015                            'entity': desc.entity.__name__.lower(), 
     1016                            'tablename': desc.tablename 
     1017                           } 
     1018                    colnames = [] 
    9981019                    for pk_col in desc.primary_keys: 
    999                         colname = self.column_format % \ 
    1000                                   {'tablename': desc.tablename, 
    1001                                    'key': pk_col.key, 
    1002                                    'entity': desc.entity.__name__.lower()} 
    1003                         # In case we have a many-to-many self-reference, we 
    1004                         # need to tweak the names of the columns so that we 
    1005                         # don't end up with twice the same column name. 
    1006                         if self.entity is self.target: 
    1007                             colname += str(num + 1) 
    1008                         colnames.append(colname) 
     1020                        data.update(key=pk_col.key) 
     1021                        colnames.append(self.column_format(data)) 
    10091022 
    10101023                for pk_col, colname in zip(desc.primary_keys, colnames): 
     
    10871100 
    10881101 
     1102def alternate_m2m_column_formatter(data): 
     1103    if data['selfref']: 
     1104        return options.NEW_M2MCOL_NAMEFORMAT % data 
     1105    else: 
     1106        return options.OLD_M2MCOL_NAMEFORMAT % data 
     1107 
     1108 
     1109def migration_aid_m2m_column_formatter(formatter): 
     1110    def debug_formatter(data): 
     1111        new_name = formatter(data) 
     1112        old_name = options.OLD_M2MCOL_NAMEFORMAT % data 
     1113        if new_name != old_name: 
     1114            complete_data = data.copy() 
     1115            #TODO: use explicit num and selfref variables 
     1116            complete_data.update(old_name=old_name, 
     1117                                 new_name=new_name, 
     1118                                 dir=data['num'] is 0 and 'local' or 'remote') 
     1119            # Specifying a stacklevel is useless in this case as the name 
     1120            # generation is triggered by setup_all(), not by the declaration 
     1121            # of the offending relationship. 
     1122            warnings.warn("The generated column name for the '%(relname)s' " 
     1123                          "relationship on the '%(entity)s' entity changed " 
     1124                          "from '%(old_name)s' to '%(new_name)s'. " 
     1125                          % complete_data) 
     1126        return new_name 
     1127    return debug_formatter 
     1128 
     1129 
    10891130def _get_join_clauses(local_table, local_cols1, local_cols2, target_table): 
    10901131    primary_join, secondary_join = [], []