1
- from typing import List , Tuple , Optional
1
+ from typing import List , Tuple , Optional , Dict , Any
2
2
from enum import Enum
3
3
4
4
from django .db import models
5
5
from django .db .models import sql
6
-
7
6
from django .db .models .constants import LOOKUP_SEP
7
+ from django .core .exceptions import SuspiciousOperation
8
8
9
9
from .fields import HStoreField
10
10
from .expressions import HStoreColumn
11
+ from .datastructures import ConditionalJoin
11
12
12
13
13
14
class ConflictAction (Enum ):
@@ -18,6 +19,43 @@ class ConflictAction(Enum):
18
19
19
20
20
21
class PostgresQuery (sql .Query ):
22
+ def add_join_conditions (self , conditions : Dict [str , Any ]) -> None :
23
+ """Adds an extra condition to an existing JOIN.
24
+
25
+ This allows you to for example do:
26
+
27
+ INNER JOIN othertable ON (mytable.id = othertable.other_id AND [extra conditions])
28
+
29
+ This does not work if nothing else in your query doesn't already generate the
30
+ initial join in the first place.
31
+ """
32
+
33
+ alias = self .get_initial_alias ()
34
+ opts = self .get_meta ()
35
+
36
+ for name , value in conditions .items ():
37
+ parts = name .split (LOOKUP_SEP )
38
+ _ , targets , _ , joins , path = self .setup_joins (parts , opts , alias , allow_many = True )
39
+ self .trim_joins (targets , joins , path )
40
+
41
+ target_table = joins [- 1 ]
42
+ field = targets [- 1 ]
43
+ join = self .alias_map .get (target_table )
44
+
45
+ if not join :
46
+ raise SuspiciousOperation ((
47
+ 'Cannot add an extra join condition for "%s", there\' s no'
48
+ 'existing join to add it to.'
49
+ ) % target_table )
50
+
51
+ # convert the Join object into a ConditionalJoin object, which
52
+ # allows us to add the extra condition
53
+ if not isinstance (join , ConditionalJoin ):
54
+ self .alias_map [target_table ] = ConditionalJoin .from_join (join )
55
+ join = self .alias_map [target_table ]
56
+
57
+ join .add_condition (field , value )
58
+
21
59
def add_fields (self , field_names : List [str ], allow_m2m : bool = True ) -> bool :
22
60
"""
23
61
Adds the given (model) fields to the select set. The field names are
0 commit comments