103 lines
3.8 KiB
Diff
103 lines
3.8 KiB
Diff
# django__django-14016
|
|
# Loki Mode Multi-Agent Patch
|
|
# Attempts: 1
|
|
|
|
--- a/django/db/models/query_utils.py
|
|
+++ b/django/db/models/query_utils.py
|
|
@@ -40,7 +40,21 @@ class Q(tree.Node):
|
|
conditional = True
|
|
|
|
def __init__(self, *args, _connector=None, _negated=False, **kwargs):
|
|
- super().__init__(children=[*args, *sorted(kwargs.items())], connector=_connector, negated=_negated)
|
|
+ children = [*args, *sorted(kwargs.items())]
|
|
+ super().__init__(children=children, connector=_connector, negated=_negated)
|
|
+
|
|
+ def _make_pickleable(self, value):
|
|
+ """Convert non-pickleable iterables to lists."""
|
|
+ if isinstance(value, (dict_keys, dict_values, dict_items)):
|
|
+ return list(value)
|
|
+ return value
|
|
+
|
|
+ def __deepcopy__(self, memo):
|
|
+ obj = type(self)()
|
|
+ obj.connector = self.connector
|
|
+ obj.negated = self.negated
|
|
+ obj.children = [(k, self._make_pickleable(v)) if isinstance(v, (dict_keys, dict_values, dict_items)) else copy.deepcopy(child, memo) for child in self.children for k, v in ([child] if not isinstance(child, tuple) else [child])]
|
|
+ return obj
|
|
|
|
def _combine(self, other, conn):
|
|
if not(isinstance(other, Q) or getattr(other, 'conditional', False) is True):
|
|
--- a/django/db/models/query_utils.py
|
|
+++ b/django/db/models/query_utils.py
|
|
@@ -1,6 +1,7 @@
|
|
"""
|
|
Various data structures used in query construction.
|
|
|
|
+import copy
|
|
Factored out from django.db.models.query to avoid making the main module very
|
|
large and/or so that they can be used by other modules without getting into
|
|
circular import difficulties.
|
|
@@ -9,6 +10,9 @@ import functools
|
|
import inspect
|
|
from collections import namedtuple
|
|
|
|
+# Import dict view types for isinstance checks
|
|
+dict_keys = type({}.keys())
|
|
+dict_values = type({}.values())
|
|
+dict_items = type({}.items())
|
|
+
|
|
from django.core.exceptions import FieldError
|
|
from django.db.models.constants import LOOKUP_SEP
|
|
from django.utils import tree
|
|
--- a/django/db/models/query_utils.py
|
|
+++ b/django/db/models/query_utils.py
|
|
@@ -1,10 +1,16 @@
|
|
"""
|
|
Various data structures used in query construction.
|
|
|
|
Factored out from django.db.models.query to avoid making the main module very
|
|
large and/or so that they can be used by other modules without getting into
|
|
circular import difficulties.
|
|
"""
|
|
+import copy
|
|
import functools
|
|
import inspect
|
|
from collections import namedtuple
|
|
|
|
+# Types for non-pickleable dict views
|
|
+dict_keys = type({}.keys())
|
|
+dict_values = type({}.values())
|
|
+dict_items = type({}.items())
|
|
+
|
|
from django.core.exceptions import FieldError
|
|
from django.db.models.constants import LOOKUP_SEP
|
|
from django.utils import tree
|
|
@@ -40,7 +46,28 @@ class Q(tree.Node):
|
|
conditional = True
|
|
|
|
def __init__(self, *args, _connector=None, _negated=False, **kwargs):
|
|
- super().__init__(children=[*args, *sorted(kwargs.items())], connector=_connector, negated=_negated)
|
|
+ children = [*args, *sorted(kwargs.items())]
|
|
+ super().__init__(children=children, connector=_connector, negated=_negated)
|
|
+
|
|
+ def _resolve_non_pickleable(self, value):
|
|
+ """Convert non-pickleable iterables to lists."""
|
|
+ if isinstance(value, (dict_keys, dict_values, dict_items)):
|
|
+ return list(value)
|
|
+ return value
|
|
+
|
|
+ def __deepcopy__(self, memo):
|
|
+ obj = type(self)()
|
|
+ obj.connector = self.connector
|
|
+ obj.negated = self.negated
|
|
+ obj.children = []
|
|
+ for child in self.children:
|
|
+ if isinstance(child, tuple) and len(child) == 2:
|
|
+ key, value = child
|
|
+ obj.children.append((key, self._resolve_non_pickleable(value)))
|
|
+ else:
|
|
+ obj.children.append(copy.deepcopy(child, memo))
|
|
+ return obj
|
|
|
|
def _combine(self, other, conn):
|
|
if not(isinstance(other, Q) or getattr(other, 'conditional', False) is True):
|