1
0
mirror of https://github.com/django/django.git synced 2025-06-05 03:29:12 +00:00

Refs #33651 -- Removed Prefetch.get_current_queryset() and get_prefetch_queryset() per deprecation timeline.

This commit is contained in:
Sarah Boyce 2024-12-12 18:12:23 +01:00
parent 55f71b195b
commit 817bc5800b
9 changed files with 21 additions and 252 deletions

View File

@ -1,6 +1,5 @@
import functools import functools
import itertools import itertools
import warnings
from collections import defaultdict from collections import defaultdict
from asgiref.sync import sync_to_async from asgiref.sync import sync_to_async
@ -21,7 +20,6 @@ from django.db.models.query_utils import PathInfo
from django.db.models.sql import AND from django.db.models.sql import AND
from django.db.models.sql.where import WhereNode from django.db.models.sql.where import WhereNode
from django.db.models.utils import AltersData from django.db.models.utils import AltersData
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.functional import cached_property from django.utils.functional import cached_property
@ -159,17 +157,6 @@ class GenericForeignKey(FieldCacheMixin, Field):
# This should never happen. I love comments like this, don't you? # This should never happen. I love comments like this, don't you?
raise Exception("Impossible arguments to GFK.get_content_type!") raise Exception("Impossible arguments to GFK.get_content_type!")
def get_prefetch_queryset(self, instances, queryset=None):
warnings.warn(
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
if queryset is None:
return self.get_prefetch_querysets(instances)
return self.get_prefetch_querysets(instances, [queryset])
def get_prefetch_querysets(self, instances, querysets=None): def get_prefetch_querysets(self, instances, querysets=None):
custom_queryset_dict = {} custom_queryset_dict = {}
if querysets is not None: if querysets is not None:
@ -626,17 +613,6 @@ def create_generic_related_manager(superclass, rel):
queryset = super().get_queryset() queryset = super().get_queryset()
return self._apply_rel_filters(queryset) return self._apply_rel_filters(queryset)
def get_prefetch_queryset(self, instances, queryset=None):
warnings.warn(
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
if queryset is None:
return self.get_prefetch_querysets(instances)
return self.get_prefetch_querysets(instances, [queryset])
def get_prefetch_querysets(self, instances, querysets=None): def get_prefetch_querysets(self, instances, querysets=None):
if querysets and len(querysets) != 1: if querysets and len(querysets) != 1:
raise ValueError( raise ValueError(

View File

@ -63,8 +63,6 @@ and two directions (forward and reverse) for a total of six combinations.
``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead. ``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead.
""" """
import warnings
from asgiref.sync import sync_to_async from asgiref.sync import sync_to_async
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
@ -81,7 +79,6 @@ from django.db.models.lookups import GreaterThan, LessThanOrEqual
from django.db.models.query import QuerySet from django.db.models.query import QuerySet
from django.db.models.query_utils import DeferredAttribute from django.db.models.query_utils import DeferredAttribute
from django.db.models.utils import AltersData, resolve_callables from django.db.models.utils import AltersData, resolve_callables
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.functional import cached_property from django.utils.functional import cached_property
@ -155,17 +152,6 @@ class ForwardManyToOneDescriptor:
def get_queryset(self, **hints): def get_queryset(self, **hints):
return self.field.remote_field.model._base_manager.db_manager(hints=hints).all() return self.field.remote_field.model._base_manager.db_manager(hints=hints).all()
def get_prefetch_queryset(self, instances, queryset=None):
warnings.warn(
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
if queryset is None:
return self.get_prefetch_querysets(instances)
return self.get_prefetch_querysets(instances, [queryset])
def get_prefetch_querysets(self, instances, querysets=None): def get_prefetch_querysets(self, instances, querysets=None):
if querysets and len(querysets) != 1: if querysets and len(querysets) != 1:
raise ValueError( raise ValueError(
@ -447,17 +433,6 @@ class ReverseOneToOneDescriptor:
def get_queryset(self, **hints): def get_queryset(self, **hints):
return self.related.related_model._base_manager.db_manager(hints=hints).all() return self.related.related_model._base_manager.db_manager(hints=hints).all()
def get_prefetch_queryset(self, instances, queryset=None):
warnings.warn(
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
if queryset is None:
return self.get_prefetch_querysets(instances)
return self.get_prefetch_querysets(instances, [queryset])
def get_prefetch_querysets(self, instances, querysets=None): def get_prefetch_querysets(self, instances, querysets=None):
if querysets and len(querysets) != 1: if querysets and len(querysets) != 1:
raise ValueError( raise ValueError(
@ -765,17 +740,6 @@ def create_reverse_many_to_one_manager(superclass, rel):
queryset = super().get_queryset() queryset = super().get_queryset()
return self._apply_rel_filters(queryset) return self._apply_rel_filters(queryset)
def get_prefetch_queryset(self, instances, queryset=None):
warnings.warn(
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
if queryset is None:
return self.get_prefetch_querysets(instances)
return self.get_prefetch_querysets(instances, [queryset])
def get_prefetch_querysets(self, instances, querysets=None): def get_prefetch_querysets(self, instances, querysets=None):
if querysets and len(querysets) != 1: if querysets and len(querysets) != 1:
raise ValueError( raise ValueError(
@ -1145,17 +1109,6 @@ def create_forward_many_to_many_manager(superclass, rel, reverse):
queryset = super().get_queryset() queryset = super().get_queryset()
return self._apply_rel_filters(queryset) return self._apply_rel_filters(queryset)
def get_prefetch_queryset(self, instances, queryset=None):
warnings.warn(
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
if queryset is None:
return self.get_prefetch_querysets(instances)
return self.get_prefetch_querysets(instances, [queryset])
def get_prefetch_querysets(self, instances, querysets=None): def get_prefetch_querysets(self, instances, querysets=None):
if querysets and len(querysets) != 1: if querysets and len(querysets) != 1:
raise ValueError( raise ValueError(

View File

@ -33,7 +33,6 @@ from django.db.models.utils import (
resolve_callables, resolve_callables,
) )
from django.utils import timezone from django.utils import timezone
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.functional import cached_property, partition from django.utils.functional import cached_property, partition
# The maximum number of results to fetch in a get() query. # The maximum number of results to fetch in a get() query.
@ -2239,16 +2238,6 @@ class Prefetch:
as_attr = self.to_attr and level == len(parts) - 1 as_attr = self.to_attr and level == len(parts) - 1
return to_attr, as_attr return to_attr, as_attr
def get_current_queryset(self, level):
warnings.warn(
"Prefetch.get_current_queryset() is deprecated. Use "
"get_current_querysets() instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
querysets = self.get_current_querysets(level)
return querysets[0] if querysets is not None else None
def get_current_querysets(self, level): def get_current_querysets(self, level):
if ( if (
self.get_current_prefetch_to(level) == self.prefetch_to self.get_current_prefetch_to(level) == self.prefetch_to
@ -2480,11 +2469,7 @@ def get_prefetcher(instance, through_attr, to_attr):
if rel_obj_descriptor: if rel_obj_descriptor:
# singly related object, descriptor object has the # singly related object, descriptor object has the
# get_prefetch_querysets() method. # get_prefetch_querysets() method.
if ( if hasattr(rel_obj_descriptor, "get_prefetch_querysets"):
hasattr(rel_obj_descriptor, "get_prefetch_querysets")
# RemovedInDjango60Warning.
or hasattr(rel_obj_descriptor, "get_prefetch_queryset")
):
prefetcher = rel_obj_descriptor prefetcher = rel_obj_descriptor
# If to_attr is set, check if the value has already been set, # If to_attr is set, check if the value has already been set,
# which is done with has_to_attr_attribute(). Do not use the # which is done with has_to_attr_attribute(). Do not use the
@ -2497,11 +2482,7 @@ def get_prefetcher(instance, through_attr, to_attr):
# the attribute on the instance rather than the class to # the attribute on the instance rather than the class to
# support many related managers # support many related managers
rel_obj = getattr(instance, through_attr) rel_obj = getattr(instance, through_attr)
if ( if hasattr(rel_obj, "get_prefetch_querysets"):
hasattr(rel_obj, "get_prefetch_querysets")
# RemovedInDjango60Warning.
or hasattr(rel_obj, "get_prefetch_queryset")
):
prefetcher = rel_obj prefetcher = rel_obj
if through_attr == to_attr: if through_attr == to_attr:
@ -2534,8 +2515,6 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
# The 'values to be matched' must be hashable as they will be used # The 'values to be matched' must be hashable as they will be used
# in a dictionary. # in a dictionary.
if hasattr(prefetcher, "get_prefetch_querysets"):
( (
rel_qs, rel_qs,
rel_obj_attr, rel_obj_attr,
@ -2546,24 +2525,6 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
) = prefetcher.get_prefetch_querysets( ) = prefetcher.get_prefetch_querysets(
instances, lookup.get_current_querysets(level) instances, lookup.get_current_querysets(level)
) )
else:
warnings.warn(
"The usage of get_prefetch_queryset() in prefetch_related_objects() is "
"deprecated. Implement get_prefetch_querysets() instead.",
RemovedInDjango60Warning,
stacklevel=2,
)
queryset = None
if querysets := lookup.get_current_querysets(level):
queryset = querysets[0]
(
rel_qs,
rel_obj_attr,
instance_attr,
single,
cache_name,
is_descriptor,
) = prefetcher.get_prefetch_queryset(instances, queryset)
# We have to handle the possibility that the QuerySet we just got back # We have to handle the possibility that the QuerySet we just got back
# contains some prefetch_related lookups. We don't want to trigger the # contains some prefetch_related lookups. We don't want to trigger the
# prefetch_related functionality by evaluating the query. Rather, we need # prefetch_related functionality by evaluating the query. Rather, we need

View File

@ -286,6 +286,14 @@ to remove usage of these features.
* The ``ChoicesMeta`` alias to ``django.db.models.enums.ChoicesType`` is * The ``ChoicesMeta`` alias to ``django.db.models.enums.ChoicesType`` is
removed. removed.
* The ``Prefetch.get_current_queryset()`` method is removed.
* The ``get_prefetch_queryset()`` method of related managers and descriptors is
removed.
* ``get_prefetcher()`` and ``prefetch_related_objects()`` no longer fallback to
``get_prefetch_queryset()``.
See :ref:`deprecated-features-5.1` for details on these changes, including how See :ref:`deprecated-features-5.1` for details on these changes, including how
to remove usage of these features. to remove usage of these features.

View File

@ -5,7 +5,6 @@ from django.contrib.contenttypes.prefetch import GenericPrefetch
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from django.test.utils import isolate_apps from django.test.utils import isolate_apps
from django.utils.deprecation import RemovedInDjango60Warning
from .models import Answer, Post, Question from .models import Answer, Post, Question
@ -99,29 +98,6 @@ class DeferredGenericRelationTests(TestCase):
obj.question obj.question
class GetPrefetchQuerySetDeprecation(TestCase):
def test_generic_relation_warning(self):
Question.objects.create(text="test")
questions = Question.objects.all()
msg = (
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead."
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
questions[0].answer_set.get_prefetch_queryset(questions)
self.assertEqual(ctx.filename, __file__)
def test_generic_foreign_key_warning(self):
answers = Answer.objects.all()
msg = (
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead."
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
Answer.question.get_prefetch_queryset(answers)
self.assertEqual(ctx.filename, __file__)
class GetPrefetchQuerySetsTests(TestCase): class GetPrefetchQuerySetsTests(TestCase):
def test_duplicate_querysets(self): def test_duplicate_querysets(self):
question = Question.objects.create(text="What is your name?") question = Question.objects.create(text="What is your name?")

View File

@ -2,7 +2,6 @@ from unittest import mock
from django.db import connection, transaction from django.db import connection, transaction
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils.deprecation import RemovedInDjango60Warning
from .models import ( from .models import (
Article, Article,
@ -577,16 +576,6 @@ class ManyToManyTests(TestCase):
) )
self.assertIn("JOIN", ctx.captured_queries[0]["sql"]) self.assertIn("JOIN", ctx.captured_queries[0]["sql"])
def test_get_prefetch_queryset_warning(self):
articles = Article.objects.all()
msg = (
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead."
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
self.a1.publications.get_prefetch_queryset(articles)
self.assertEqual(ctx.filename, __file__)
def test_get_prefetch_querysets_invalid_querysets_length(self): def test_get_prefetch_querysets_invalid_querysets_length(self):
articles = Article.objects.all() articles = Article.objects.all()
msg = ( msg = (

View File

@ -4,7 +4,6 @@ from copy import deepcopy
from django.core.exceptions import FieldError, MultipleObjectsReturned from django.core.exceptions import FieldError, MultipleObjectsReturned
from django.db import IntegrityError, models, transaction from django.db import IntegrityError, models, transaction
from django.test import TestCase from django.test import TestCase
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
from .models import ( from .models import (
@ -887,29 +886,6 @@ class ManyToOneTests(TestCase):
with self.assertRaisesMessage(TypeError, msg): with self.assertRaisesMessage(TypeError, msg):
usa.cities.set([chicago.pk]) usa.cities.set([chicago.pk])
def test_get_prefetch_queryset_warning(self):
City.objects.create(name="Chicago")
cities = City.objects.all()
msg = (
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead."
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
City.country.get_prefetch_queryset(cities)
self.assertEqual(ctx.filename, __file__)
def test_get_prefetch_queryset_reverse_warning(self):
usa = Country.objects.create(name="United States")
City.objects.create(name="Chicago")
countries = Country.objects.all()
msg = (
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead."
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
usa.cities.get_prefetch_queryset(countries)
self.assertEqual(ctx.filename, __file__)
def test_get_prefetch_querysets_invalid_querysets_length(self): def test_get_prefetch_querysets_invalid_querysets_length(self):
City.objects.create(name="Chicago") City.objects.create(name="Chicago")
cities = City.objects.all() cities = City.objects.all()

View File

@ -1,6 +1,5 @@
from django.db import IntegrityError, connection, transaction from django.db import IntegrityError, connection, transaction
from django.test import TestCase from django.test import TestCase
from django.utils.deprecation import RemovedInDjango60Warning
from .models import ( from .models import (
Bar, Bar,
@ -606,16 +605,6 @@ class OneToOneTests(TestCase):
self.b1.save() self.b1.save()
self.assertEqual(self.b1.place, self.p2) self.assertEqual(self.b1.place, self.p2)
def test_get_prefetch_queryset_warning(self):
places = Place.objects.all()
msg = (
"get_prefetch_queryset() is deprecated. Use get_prefetch_querysets() "
"instead."
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
Place.bar.get_prefetch_queryset(places)
self.assertEqual(ctx.filename, __file__)
def test_get_prefetch_querysets_invalid_querysets_length(self): def test_get_prefetch_querysets_invalid_querysets_length(self):
places = Place.objects.all() places = Place.objects.all()
msg = ( msg = (

View File

@ -4,18 +4,15 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import NotSupportedError, connection from django.db import NotSupportedError, connection
from django.db.models import Prefetch, QuerySet, prefetch_related_objects from django.db.models import Prefetch, QuerySet, prefetch_related_objects
from django.db.models.fields.related import ForwardManyToOneDescriptor from django.db.models.query import get_prefetcher
from django.db.models.query import get_prefetcher, prefetch_one_level
from django.db.models.sql import Query from django.db.models.sql import Query
from django.test import ( from django.test import (
TestCase, TestCase,
ignore_warnings,
override_settings, override_settings,
skipIfDBFeature, skipIfDBFeature,
skipUnlessDBFeature, skipUnlessDBFeature,
) )
from django.test.utils import CaptureQueriesContext from django.test.utils import CaptureQueriesContext
from django.utils.deprecation import RemovedInDjango60Warning
from .models import ( from .models import (
Article, Article,
@ -2013,59 +2010,3 @@ class PrefetchLimitTests(TestDataMixin, TestCase):
with self.subTest(book=book): with self.subTest(book=book):
self.assertEqual(len(book.authors_sliced), 1) self.assertEqual(len(book.authors_sliced), 1)
self.assertIn(book.authors_sliced[0], list(book.authors.all())) self.assertIn(book.authors_sliced[0], list(book.authors.all()))
class DeprecationTests(TestCase):
def test_get_current_queryset_warning(self):
msg = (
"Prefetch.get_current_queryset() is deprecated. Use "
"get_current_querysets() instead."
)
authors = Author.objects.all()
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
self.assertEqual(
Prefetch("authors", authors).get_current_queryset(1),
authors,
)
self.assertEqual(ctx.filename, __file__)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg) as ctx:
self.assertIsNone(Prefetch("authors").get_current_queryset(1))
self.assertEqual(ctx.filename, __file__)
@ignore_warnings(category=RemovedInDjango60Warning)
def test_prefetch_one_level_fallback(self):
class NoGetPrefetchQuerySetsDescriptor(ForwardManyToOneDescriptor):
def get_prefetch_queryset(self, instances, queryset=None):
if queryset is None:
return super().get_prefetch_querysets(instances)
return super().get_prefetch_querysets(instances, [queryset])
def __getattribute__(self, name):
if name == "get_prefetch_querysets":
raise AttributeError
return super().__getattribute__(name)
house = House.objects.create()
room = Room.objects.create(house=house)
house.main_room = room
house.save()
# prefetch_one_level() fallbacks to get_prefetch_queryset().
prefetcher = NoGetPrefetchQuerySetsDescriptor(Room._meta.get_field("house"))
obj_list, additional_lookups = prefetch_one_level(
[room],
prefetcher,
Prefetch("house", House.objects.all()),
0,
)
self.assertEqual(obj_list, [house])
self.assertEqual(additional_lookups, [])
obj_list, additional_lookups = prefetch_one_level(
[room],
prefetcher,
Prefetch("house"),
0,
)
self.assertEqual(obj_list, [house])
self.assertEqual(additional_lookups, [])