@@ -115,26 +115,45 @@ def add_model_init_hook(ctx: ClassDefContext) -> None:
115115 if not (isinstance (stmt , AssignmentStmt ) and len (stmt .lvalues ) == 1 and isinstance (stmt .lvalues [0 ], NameExpr )):
116116 continue
117117
118+ # We currently only handle setting __tablename__ as a class attribute, and not through a property.
118119 if stmt .lvalues [0 ].name == "__tablename__" and isinstance (stmt .rvalue , StrExpr ):
119120 ctx .cls .info .metadata .setdefault ('sqlalchemy' , {})['tablename' ] = stmt .rvalue .value
120121
121122 if isinstance (stmt .rvalue , CallExpr ) and stmt .rvalue .callee .fullname == COLUMN_NAME :
122- colname = stmt .lvalues [0 ].name
123- has_explicit_colname = stmt .rvalue
124- ctx .cls .info .metadata .setdefault ('sqlalchemy' , {}).setdefault ('columns' , []).append (colname )
123+ # Save columns. The name of a column on the db side can be different from the one inside the SA model.
124+ sa_column_name = stmt .lvalues [0 ].name
125+
126+ db_column_name = None # type: Optional[str]
127+ if 'name' in stmt .rvalue .arg_names :
128+ name_str_expr = stmt .rvalue .args [stmt .rvalue .arg_names .index ('name' )]
129+ assert isinstance (name_str_expr , StrExpr )
130+ db_column_name = name_str_expr .value
131+ else :
132+ if len (stmt .rvalue .args ) >= 1 and isinstance (stmt .rvalue .args [0 ], StrExpr ):
133+ db_column_name = stmt .rvalue .args [0 ].value
134+
135+ ctx .cls .info .metadata .setdefault ('sqlalchemy' , {}).setdefault ('columns' , []).append (
136+ {"sa_name" : sa_column_name , "db_name" : db_column_name or sa_column_name }
137+ )
138+
139+ # Save foreign keys.
125140 for arg in stmt .rvalue .args :
126141 if isinstance (arg , CallExpr ) and arg .callee .fullname == FOREIGN_KEY_NAME and len (arg .args ) >= 1 :
127142 fk = arg .args [0 ]
128143 if isinstance (fk , StrExpr ):
129- * _ , parent_table , parent_col = fk .value .split ("." )
130- ctx .cls .info .metadata .setdefault ('sqlalchemy' , {}).setdefault ('foreign_keys' , {})[colname ] = {
131- "column" : parent_col ,
132- "table" : parent_table
144+ * r , parent_table_name , parent_db_col_name = fk .value .split ("." )
145+ assert len (r ) <= 1
146+ ctx .cls .info .metadata .setdefault ('sqlalchemy' , {}).setdefault ('foreign_keys' ,
147+ {})[sa_column_name ] = {
148+ "db_name" : parent_db_col_name ,
149+ "table_name" : parent_table_name ,
150+ "schema" : r [0 ] if r else None
133151 }
134152 elif isinstance (fk , MemberExpr ):
135- ctx .cls .info .metadata .setdefault ('sqlalchemy' , {}).setdefault ('foreign_keys' , {})[colname ] = {
136- "column" : fk .name ,
137- "model" : fk .expr .fullname
153+ ctx .cls .info .metadata .setdefault ('sqlalchemy' , {}).setdefault ('foreign_keys' ,
154+ {})[sa_column_name ] = {
155+ "sa_name" : fk .name ,
156+ "model_fullname" : fk .expr .fullname
138157 }
139158
140159 # Also add a selection of auto-generated attributes.
@@ -414,10 +433,10 @@ class User(Base):
414433# We really need to add this to TypeChecker API
415434def parse_bool (expr : Expression ) -> Optional [bool ]:
416435 if isinstance (expr , NameExpr ):
417- if expr .fullname == 'builtins.True' :
418- return True
419- if expr .fullname == 'builtins.False' :
420- return False
436+ if expr .fullname == 'builtins.True' :
437+ return True
438+ if expr .fullname == 'builtins.False' :
439+ return False
421440 return None
422441
423442
0 commit comments