mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Fixed #16759 -- Remove use of __deepcopy__ in qs.clone()
The original problem was that queryset cloning was really expensive when filtering with F() clauses. The __deepcopy__ went too deep copying _meta attributes of the models used. To fix this the use of __deepcopy__ in qs cloning was removed. This commit results in some speed improvements across the djangobench benchmark suite. Most query_* tests are 20-30% faster, save() is 50% faster and finally complex filtering situations can see 2x to order of magnitude improvments. Thanks to Suor, Alex and lrekucki for valuable feedback.
This commit is contained in:
parent
bb7f34d619
commit
23ca3a0194
4 changed files with 81 additions and 7 deletions
|
@ -1919,6 +1919,7 @@ class SubqueryTests(TestCase):
|
|||
|
||||
|
||||
class CloneTests(TestCase):
|
||||
|
||||
def test_evaluated_queryset_as_argument(self):
|
||||
"#13227 -- If a queryset is already evaluated, it can still be used as a query arg"
|
||||
n = Note(note='Test1', misc='misc')
|
||||
|
@ -1933,6 +1934,39 @@ class CloneTests(TestCase):
|
|||
# that query in a way that involves cloning.
|
||||
self.assertEqual(ExtraInfo.objects.filter(note__in=n_list)[0].info, 'good')
|
||||
|
||||
def test_no_model_options_cloning(self):
|
||||
"""
|
||||
Test that cloning a queryset does not get out of hand. While complete
|
||||
testing is impossible, this is a sanity check against invalid use of
|
||||
deepcopy. refs #16759.
|
||||
"""
|
||||
opts_class = type(Note._meta)
|
||||
note_deepcopy = getattr(opts_class, "__deepcopy__", None)
|
||||
opts_class.__deepcopy__ = lambda obj, memo: self.fail("Model options shouldn't be cloned.")
|
||||
try:
|
||||
Note.objects.filter(pk__lte=F('pk') + 1).all()
|
||||
finally:
|
||||
if note_deepcopy is None:
|
||||
delattr(opts_class, "__deepcopy__")
|
||||
else:
|
||||
opts_class.__deepcopy__ = note_deepcopy
|
||||
|
||||
def test_no_fields_cloning(self):
|
||||
"""
|
||||
Test that cloning a queryset does not get out of hand. While complete
|
||||
testing is impossible, this is a sanity check against invalid use of
|
||||
deepcopy. refs #16759.
|
||||
"""
|
||||
opts_class = type(Note._meta.get_field_by_name("misc")[0])
|
||||
note_deepcopy = getattr(opts_class, "__deepcopy__", None)
|
||||
opts_class.__deepcopy__ = lambda obj, memo: self.fail("Model fields shouldn't be cloned")
|
||||
try:
|
||||
Note.objects.filter(note=F('misc')).all()
|
||||
finally:
|
||||
if note_deepcopy is None:
|
||||
delattr(opts_class, "__deepcopy__")
|
||||
else:
|
||||
opts_class.__deepcopy__ = note_deepcopy
|
||||
|
||||
class EmptyQuerySetTests(TestCase):
|
||||
def test_emptyqueryset_values(self):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue