popoto.models.q¶
popoto.models.q
¶
Q Objects for Complex Query Expressions.
This module provides Django-style Q objects that enable complex query logic with OR, AND, and NOT operators. Q objects can be combined using Python operators to build expressive filter expressions.
Usage Examples:¶
from popoto import Q
# OR logic - find active OR premium users
users = User.query.filter(Q(status="active") | Q(type="premium"))
# AND logic (explicit) - same as passing multiple kwargs
users = User.query.filter(Q(status="active") & Q(rating__gt=4.0))
# Complex combinations - active OR premium, with high rating
users = User.query.filter(
(Q(status="active") | Q(type="premium")) & Q(rating__gt=3.0)
)
# Negation - find users who are NOT inactive
users = User.query.filter(~Q(status="inactive"))
Design Notes:¶
Q objects build an expression tree that is evaluated at query time. Each Q object can be either:
- A leaf node containing filter kwargs (e.g., Q(status="active"))
- An internal node combining child Q objects with AND/OR connectors
The Query class evaluates Q expressions by recursively computing result sets: - AND: set intersection of children's results - OR: set union of children's results - NOT: set difference from all keys
This approach leverages Redis's efficient set operations while providing a familiar Django-like query interface.
Q
¶
Django-style Q object for complex query expressions.
Q objects enable OR logic and complex query combinations that aren't possible with simple kwargs. They can be combined using Python operators:
|(OR): Union of results&(AND): Intersection of results~(NOT): Negation (exclusion from all results)
Attributes:
| Name | Type | Description |
|---|---|---|
filters |
Dict of filter kwargs for leaf nodes |
|
connector |
'AND' or 'OR' for combined Q objects |
|
children |
List of child Q objects for combined expressions |
|
negated |
Whether this Q object is negated |
Example
Basic Q object¶
q = Q(status="active")
Combined with OR¶
q = Q(status="active") | Q(type="premium")
Negated¶
q = ~Q(status="inactive")
Complex expression¶
q = (Q(status="active") | Q(type="premium")) & ~Q(rating__lt=2.0)
Source code in src/popoto/models/q.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | |
is_leaf()
¶
Check if this Q object is a leaf node (has filters, no children).
Returns:
| Type | Description |
|---|---|
|
True if this Q object has filter kwargs and no children. |
is_empty()
¶
Check if this Q object has no filters and no children.
Returns:
| Type | Description |
|---|---|
|
True if this Q object is effectively a no-op. |
evaluate_q(query_instance, q_obj, all_keys=None)
¶
Evaluate a Q object expression tree and return matching Redis keys.
This function recursively evaluates Q object trees, computing result sets at each level using set operations:
- Leaf nodes: Execute filter query and return matching keys
- AND nodes: Return intersection of children's results
- OR nodes: Return union of children's results
- Negated nodes: Return difference from all_keys
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query_instance
|
The Query instance to execute filters against |
required | |
q_obj
|
The Q object to evaluate |
required | |
all_keys
|
Set of all Redis keys for the model (used for negation). If None, will be fetched when needed for NOT operations. |
None
|
Returns:
| Type | Description |
|---|---|
|
Set of Redis keys matching the Q expression. |
Note
This function is called internally by Query.filter() when Q objects are passed as arguments. Users should not need to call it directly.