mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #35690 -- Add support for calling QuerySet.in_bulk() after QuerySet.values()
This commit is contained in:
parent
5ed72087c4
commit
084b4f10c2
@ -1119,6 +1119,29 @@ class QuerySet(AltersData):
|
|||||||
"in_bulk()'s field_name must be a unique field but %r isn't."
|
"in_bulk()'s field_name must be a unique field but %r isn't."
|
||||||
% field_name
|
% field_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if issubclass(self._iterable_class, ModelIterable):
|
||||||
|
|
||||||
|
def _get_key(row):
|
||||||
|
# Will raise an unhelpful AttributeError if field_name is deferred
|
||||||
|
# We could catch this earlier and raise a TypeError
|
||||||
|
return getattr(row, field_name)
|
||||||
|
|
||||||
|
elif issubclass(self._iterable_class, ValuesIterable):
|
||||||
|
# If field_name wasn't explicitly included, include it anyways
|
||||||
|
if field_name not in self.query.values_select:
|
||||||
|
return self.values(field_name, *self.query.values_select).in_bulk(
|
||||||
|
id_list=id_list, field_name=field_name
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_key(row):
|
||||||
|
return row[field_name]
|
||||||
|
|
||||||
|
else:
|
||||||
|
# NamedValuesListIterable should work in theory,
|
||||||
|
# but in practice it's very clunky.
|
||||||
|
raise TypeError("in_bulk() cannot be used with %r." % self._iterable_class)
|
||||||
|
|
||||||
if id_list is not None:
|
if id_list is not None:
|
||||||
if not id_list:
|
if not id_list:
|
||||||
return {}
|
return {}
|
||||||
@ -1136,7 +1159,7 @@ class QuerySet(AltersData):
|
|||||||
qs = self.filter(**{filter_key: id_list})
|
qs = self.filter(**{filter_key: id_list})
|
||||||
else:
|
else:
|
||||||
qs = self._chain()
|
qs = self._chain()
|
||||||
return {getattr(obj, field_name): obj for obj in qs}
|
return {_get_key(obj): obj for obj in qs}
|
||||||
|
|
||||||
async def ain_bulk(self, id_list=None, *, field_name="pk"):
|
async def ain_bulk(self, id_list=None, *, field_name="pk"):
|
||||||
return await sync_to_async(self.in_bulk)(
|
return await sync_to_async(self.in_bulk)(
|
||||||
|
@ -205,6 +205,23 @@ class LookupTests(TestCase):
|
|||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Article.objects.in_bulk(headline__startswith="Blah")
|
Article.objects.in_bulk(headline__startswith="Blah")
|
||||||
|
|
||||||
|
def test_in_bulk_values(self):
|
||||||
|
bulk = Article.objects.values().in_bulk([self.a1.id])
|
||||||
|
self.assertIsInstance(bulk[self.a1.id], dict)
|
||||||
|
|
||||||
|
def test_in_bulk_values_without_pk(self):
|
||||||
|
bulk = Article.objects.values("headline").in_bulk([self.a1.id])
|
||||||
|
self.assertIn("pk", bulk[self.a1.id])
|
||||||
|
|
||||||
|
def test_in_bulk_values_list(self):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
Article.objects.values_list().in_bulk([self.a1.id])
|
||||||
|
|
||||||
|
def test_in_bulk_values_list_named(self) -> None:
|
||||||
|
# At some point this could return tuples
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
Article.objects.values_list(named=True).in_bulk([self.a1.id])
|
||||||
|
|
||||||
def test_in_bulk_lots_of_ids(self):
|
def test_in_bulk_lots_of_ids(self):
|
||||||
test_range = 2000
|
test_range = 2000
|
||||||
max_query_params = connection.features.max_query_params
|
max_query_params = connection.features.max_query_params
|
||||||
|
Loading…
Reference in New Issue
Block a user