django-cte 2.0.1.dev20251006193645__tar.gz → 2.0.1.dev20251120124810__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cte
3
- Version: 2.0.1.dev20251006193645
3
+ Version: 2.0.1.dev20251120124810
4
4
  Summary: Common Table Expressions (CTE) for Django
5
5
  Author-email: Daniel Miller <millerdev@gmail.com>
6
6
  Requires-Python: >= 3.9
@@ -1,4 +1,4 @@
1
1
  from .cte import CTE, with_cte, CTEManager, CTEQuerySet, With # noqa
2
2
 
3
- __version__ = "2.0.1.dev20251006193645"
3
+ __version__ = "2.0.1.dev20251120124810"
4
4
  __all__ = ["CTE", "with_cte"]
@@ -1,5 +1,6 @@
1
1
  from copy import copy
2
2
 
3
+ import django
3
4
  from django.db.models import Manager, sql
4
5
  from django.db.models.expressions import Ref
5
6
  from django.db.models.query import Q, QuerySet, ValuesIterable
@@ -45,21 +46,30 @@ class CTE:
45
46
  """
46
47
 
47
48
  def __init__(self, queryset, name="cte", materialized=False):
48
- self.query = None if queryset is None else queryset.query
49
+ self._set_queryset(queryset)
49
50
  self.name = name
50
51
  self.col = CTEColumns(self)
51
52
  self.materialized = materialized
52
53
 
53
54
  def __getstate__(self):
54
- return (self.query, self.name, self.materialized)
55
+ return (self.query, self.name, self.materialized, self._iterable_class)
55
56
 
56
57
  def __setstate__(self, state):
57
- self.query, self.name, self.materialized = state
58
+ if len(state) == 3:
59
+ # Keep compatibility with the previous serialization method
60
+ self.query, self.name, self.materialized = state
61
+ self._iterable_class = ValuesIterable
62
+ else:
63
+ self.query, self.name, self.materialized, self._iterable_class = state
58
64
  self.col = CTEColumns(self)
59
65
 
60
66
  def __repr__(self):
61
67
  return f"<{type(self).__name__} {self.name}>"
62
68
 
69
+ def _set_queryset(self, queryset):
70
+ self.query = None if queryset is None else queryset.query
71
+ self._iterable_class = getattr(queryset, "_iterable_class", ValuesIterable)
72
+
63
73
  @classmethod
64
74
  def recursive(cls, make_cte_queryset, name="cte", materialized=False):
65
75
  """Recursive Common Table Expression
@@ -73,7 +83,7 @@ class CTE:
73
83
  :returns: The fully constructed recursive cte object.
74
84
  """
75
85
  cte = cls(None, name, materialized)
76
- cte.query = make_cte_queryset(cte).query
86
+ cte._set_queryset(make_cte_queryset(cte))
77
87
  return cte
78
88
 
79
89
  def join(self, model_or_queryset, *filter_q, **filter_kw):
@@ -105,7 +115,12 @@ class CTE:
105
115
  q_object = Q(*filter_q, **filter_kw)
106
116
  map = query.alias_map
107
117
  existing_inner = set(a for a in map if map[a].join_type == INNER)
108
- on_clause, _ = query._add_q(q_object, query.used_aliases)
118
+ if django.VERSION >= (5, 2):
119
+ on_clause, _ = query._add_q(
120
+ q_object, query.used_aliases, update_join_types=(join_type == INNER)
121
+ )
122
+ else:
123
+ on_clause, _ = query._add_q(q_object, query.used_aliases)
109
124
  query.demote_joins(existing_inner)
110
125
 
111
126
  parent = query.get_initial_alias()
@@ -124,24 +139,30 @@ class CTE:
124
139
  """
125
140
  cte_query = self.query
126
141
  qs = cte_query.model._default_manager.get_queryset()
142
+ qs._iterable_class = self._iterable_class
143
+ qs._fields = () # Allow any field names to be used in further annotations
127
144
 
128
145
  query = jit_mixin(sql.Query(cte_query.model), CTEQuery)
129
146
  query.join(BaseTable(self.name, None))
130
147
  query.default_cols = cte_query.default_cols
131
148
  query.deferred_loading = cte_query.deferred_loading
132
- if cte_query.values_select:
149
+
150
+ if django.VERSION < (5, 2) and cte_query.values_select:
133
151
  query.set_values(cte_query.values_select)
134
- qs._iterable_class = ValuesIterable
152
+
135
153
  if cte_query.annotations:
136
154
  for alias, value in cte_query.annotations.items():
137
155
  col = CTEColumnRef(alias, self.name, value.output_field)
138
156
  query.add_annotation(col, alias)
139
157
  query.annotation_select_mask = cte_query.annotation_select_mask
140
- for alias in getattr(cte_query, "selected", None) or ():
141
- if alias not in cte_query.annotations:
142
- output_field = cte_query.resolve_ref(alias).output_field
143
- col = CTEColumnRef(alias, self.name, output_field)
144
- query.add_annotation(col, alias)
158
+
159
+ if selected := getattr(cte_query, "selected", None):
160
+ for alias in selected:
161
+ if alias not in cte_query.annotations:
162
+ output_field = cte_query.resolve_ref(alias).output_field
163
+ col = CTEColumnRef(alias, self.name, output_field)
164
+ query.add_annotation(col, alias)
165
+ query.selected = {alias: alias for alias in selected}
145
166
 
146
167
  qs.query = query
147
168
  return qs