| 1182 | def setup_join(self, opts, field, model, direct, m2m, name, joins, |
| 1183 | exclusions, dupe_set, alias, dupe_multis, can_reuse=None): |
| 1184 | """ |
| 1185 | Compute a single table join. |
| 1186 | """ |
| 1187 | int_alias = None |
| 1188 | |
| 1189 | if model: |
| 1190 | # The field lives on a base class of the current model. |
| 1191 | for int_model in opts.get_base_chain(model): |
| 1192 | lhs_col = opts.parents[int_model].column |
| 1193 | dedupe = lhs_col in opts.duplicate_targets |
| 1194 | if dedupe: |
| 1195 | exclusions.update(self.dupe_avoidance.get( |
| 1196 | (id(opts), lhs_col), ())) |
| 1197 | dupe_set.add((opts, lhs_col)) |
| 1198 | opts = int_model._meta |
| 1199 | alias = self.join((alias, opts.db_table, lhs_col, |
| 1200 | opts.pk.column), exclusions=exclusions) |
| 1201 | joins.append(alias) |
| 1202 | exclusions.add(alias) |
| 1203 | for (dupe_opts, dupe_col) in dupe_set: |
| 1204 | self.update_dupe_avoidance(dupe_opts, dupe_col, alias) |
| 1205 | cached_data = opts._join_cache.get(name) |
| 1206 | orig_opts = opts |
| 1207 | dupe_col = direct and field.column or field.field.column |
| 1208 | dedupe = dupe_col in opts.duplicate_targets |
| 1209 | if dupe_set or dedupe: |
| 1210 | if dedupe: |
| 1211 | dupe_set.add((opts, dupe_col)) |
| 1212 | exclusions.update(self.dupe_avoidance.get((id(opts), dupe_col), |
| 1213 | ())) |
| 1214 | |
| 1215 | if direct: |
| 1216 | if m2m: |
| 1217 | # Many-to-many field defined on the current model. |
| 1218 | if cached_data: |
| 1219 | (table1, from_col1, to_col1, table2, from_col2, |
| 1220 | to_col2, opts, target) = cached_data |
| 1221 | else: |
| 1222 | table1 = field.m2m_db_table() |
| 1223 | from_col1 = opts.pk.column |
| 1224 | to_col1 = field.m2m_column_name() |
| 1225 | opts = field.rel.to._meta |
| 1226 | table2 = opts.db_table |
| 1227 | from_col2 = field.m2m_reverse_name() |
| 1228 | to_col2 = opts.pk.column |
| 1229 | target = opts.pk |
| 1230 | orig_opts._join_cache[name] = (table1, from_col1, |
| 1231 | to_col1, table2, from_col2, to_col2, opts, |
| 1232 | target) |
| 1233 | |
| 1234 | int_alias = self.join((alias, table1, from_col1, to_col1), |
| 1235 | dupe_multis, exclusions, nullable=True, |
| 1236 | reuse=can_reuse) |
| 1237 | alias = self.join((int_alias, table2, from_col2, to_col2), |
| 1238 | dupe_multis, exclusions, nullable=True, |
| 1239 | reuse=can_reuse) |
| 1240 | joins.extend([int_alias, alias]) |
| 1241 | elif field.rel: |
| 1242 | # One-to-one or many-to-one field |
| 1243 | if cached_data: |
| 1244 | (table, from_col, to_col, opts, target) = cached_data |
| 1245 | else: |
| 1246 | opts = field.rel.to._meta |
| 1247 | target = field.rel.get_related_field() |
| 1248 | table = opts.db_table |
| 1249 | from_col = field.column |
| 1250 | to_col = target.column |
| 1251 | orig_opts._join_cache[name] = (table, from_col, to_col, |
| 1252 | opts, target) |
| 1253 | alias = self.join((alias, table, from_col, to_col), |
| 1254 | exclusions=exclusions, nullable=field.null) |
| 1255 | joins.append(alias) |
| 1256 | else: |
| 1257 | # Non-relation fields. |
| 1258 | target = field |
| 1259 | return True, int_alias, alias, field, target, opts |
| 1260 | else: |
| 1261 | orig_field = field |
| 1262 | field = field.field |
| 1263 | if m2m: |
| 1264 | # Many-to-many field defined on the target model. |
| 1265 | if cached_data: |
| 1266 | (table1, from_col1, to_col1, table2, from_col2, |
| 1267 | to_col2, opts, target) = cached_data |
| 1268 | else: |
| 1269 | table1 = field.m2m_db_table() |
| 1270 | from_col1 = opts.pk.column |
| 1271 | to_col1 = field.m2m_reverse_name() |
| 1272 | opts = orig_field.opts |
| 1273 | table2 = opts.db_table |
| 1274 | from_col2 = field.m2m_column_name() |
| 1275 | to_col2 = opts.pk.column |
| 1276 | target = opts.pk |
| 1277 | orig_opts._join_cache[name] = (table1, from_col1, |
| 1278 | to_col1, table2, from_col2, to_col2, opts, |
| 1279 | target) |
| 1280 | |
| 1281 | int_alias = self.join((alias, table1, from_col1, to_col1), |
| 1282 | dupe_multis, exclusions, nullable=True, |
| 1283 | reuse=can_reuse) |
| 1284 | alias = self.join((int_alias, table2, from_col2, to_col2), |
| 1285 | dupe_multis, exclusions, nullable=True, |
| 1286 | reuse=can_reuse) |
| 1287 | joins.extend([int_alias, alias]) |
| 1288 | else: |
| 1289 | # One-to-many field (ForeignKey defined on the target model) |
| 1290 | if cached_data: |
| 1291 | (table, from_col, to_col, opts, target) = cached_data |
| 1292 | else: |
| 1293 | local_field = opts.get_field_by_name( |
| 1294 | field.rel.field_name)[0] |
| 1295 | opts = orig_field.opts |
| 1296 | table = opts.db_table |
| 1297 | from_col = local_field.column |
| 1298 | to_col = field.column |
| 1299 | target = opts.pk |
| 1300 | orig_opts._join_cache[name] = (table, from_col, to_col, |
| 1301 | opts, target) |
| 1302 | |
| 1303 | alias = self.join((alias, table, from_col, to_col), |
| 1304 | dupe_multis, exclusions, nullable=True, |
| 1305 | reuse=can_reuse) |
| 1306 | joins.append(alias) |
| 1307 | |
| 1308 | for (dupe_opts, dupe_col) in dupe_set: |
| 1309 | if int_alias is None: |
| 1310 | self.update_dupe_avoidance(dupe_opts, dupe_col, alias) |
| 1311 | else: |
| 1312 | self.update_dupe_avoidance(dupe_opts, dupe_col, int_alias) |
| 1313 | |
| 1314 | return False, int_alias, alias, field, target, opts |
| 1315 | |
1242 | | if direct: |
1243 | | if m2m: |
1244 | | # Many-to-many field defined on the current model. |
1245 | | if cached_data: |
1246 | | (table1, from_col1, to_col1, table2, from_col2, |
1247 | | to_col2, opts, target) = cached_data |
1248 | | else: |
1249 | | table1 = field.m2m_db_table() |
1250 | | from_col1 = opts.pk.column |
1251 | | to_col1 = field.m2m_column_name() |
1252 | | opts = field.rel.to._meta |
1253 | | table2 = opts.db_table |
1254 | | from_col2 = field.m2m_reverse_name() |
1255 | | to_col2 = opts.pk.column |
1256 | | target = opts.pk |
1257 | | orig_opts._join_cache[name] = (table1, from_col1, |
1258 | | to_col1, table2, from_col2, to_col2, opts, |
1259 | | target) |
1260 | | |
1261 | | int_alias = self.join((alias, table1, from_col1, to_col1), |
1262 | | dupe_multis, exclusions, nullable=True, |
1263 | | reuse=can_reuse) |
1264 | | alias = self.join((int_alias, table2, from_col2, to_col2), |
1265 | | dupe_multis, exclusions, nullable=True, |
1266 | | reuse=can_reuse) |
1267 | | joins.extend([int_alias, alias]) |
1268 | | elif field.rel: |
1269 | | # One-to-one or many-to-one field |
1270 | | if cached_data: |
1271 | | (table, from_col, to_col, opts, target) = cached_data |
1272 | | else: |
1273 | | opts = field.rel.to._meta |
1274 | | target = field.rel.get_related_field() |
1275 | | table = opts.db_table |
1276 | | from_col = field.column |
1277 | | to_col = target.column |
1278 | | orig_opts._join_cache[name] = (table, from_col, to_col, |
1279 | | opts, target) |
1280 | | |
1281 | | alias = self.join((alias, table, from_col, to_col), |
1282 | | exclusions=exclusions, nullable=field.null) |
1283 | | joins.append(alias) |
1284 | | else: |
1285 | | # Non-relation fields. |
1286 | | target = field |
1287 | | break |
1288 | | else: |
1289 | | orig_field = field |
1290 | | field = field.field |
1291 | | if m2m: |
1292 | | # Many-to-many field defined on the target model. |
1293 | | if cached_data: |
1294 | | (table1, from_col1, to_col1, table2, from_col2, |
1295 | | to_col2, opts, target) = cached_data |
1296 | | else: |
1297 | | table1 = field.m2m_db_table() |
1298 | | from_col1 = opts.pk.column |
1299 | | to_col1 = field.m2m_reverse_name() |
1300 | | opts = orig_field.opts |
1301 | | table2 = opts.db_table |
1302 | | from_col2 = field.m2m_column_name() |
1303 | | to_col2 = opts.pk.column |
1304 | | target = opts.pk |
1305 | | orig_opts._join_cache[name] = (table1, from_col1, |
1306 | | to_col1, table2, from_col2, to_col2, opts, |
1307 | | target) |
1308 | | |
1309 | | int_alias = self.join((alias, table1, from_col1, to_col1), |
1310 | | dupe_multis, exclusions, nullable=True, |
1311 | | reuse=can_reuse) |
1312 | | alias = self.join((int_alias, table2, from_col2, to_col2), |
1313 | | dupe_multis, exclusions, nullable=True, |
1314 | | reuse=can_reuse) |
1315 | | joins.extend([int_alias, alias]) |
1316 | | else: |
1317 | | # One-to-many field (ForeignKey defined on the target model) |
1318 | | if cached_data: |
1319 | | (table, from_col, to_col, opts, target) = cached_data |
1320 | | else: |
1321 | | local_field = opts.get_field_by_name( |
1322 | | field.rel.field_name)[0] |
1323 | | opts = orig_field.opts |
1324 | | table = opts.db_table |
1325 | | from_col = local_field.column |
1326 | | to_col = field.column |
1327 | | target = opts.pk |
1328 | | orig_opts._join_cache[name] = (table, from_col, to_col, |
1329 | | opts, target) |
1330 | | |
1331 | | alias = self.join((alias, table, from_col, to_col), |
1332 | | dupe_multis, exclusions, nullable=True, |
1333 | | reuse=can_reuse) |
1334 | | joins.append(alias) |
1335 | | |
1336 | | for (dupe_opts, dupe_col) in dupe_set: |
1337 | | try: |
1338 | | self.update_dupe_avoidance(dupe_opts, dupe_col, int_alias) |
1339 | | except NameError: |
1340 | | self.update_dupe_avoidance(dupe_opts, dupe_col, alias) |
1341 | | |
| 1365 | final, int_alias, alias, field, target, opts = self.setup_join(opts, |
| 1366 | field, model, direct, m2m, name, joins, exclusions, |
| 1367 | dupe_set, alias, dupe_multis, can_reuse=can_reuse) |
| 1368 | if final: |
| 1369 | break |
| 1370 | |