mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-10 19:56:59 +03:00
Group queries for SlugRelatedField many serializers
This commit is contained in:
parent
d6ca95f4c7
commit
b72027fcdb
|
@ -4,7 +4,7 @@ from operator import attrgetter
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||||
from django.db.models import Manager
|
from django.db.models import F, Manager
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.urls import NoReverseMatch, Resolver404, get_script_prefix, resolve
|
from django.urls import NoReverseMatch, Resolver404, get_script_prefix, resolve
|
||||||
from django.utils.encoding import smart_str, uri_to_iri
|
from django.utils.encoding import smart_str, uri_to_iri
|
||||||
|
@ -458,15 +458,26 @@ class SlugRelatedField(RelatedField):
|
||||||
self.slug_field = slug_field
|
self.slug_field = slug_field
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_many_internal_value(self, data):
|
||||||
queryset = self.get_queryset()
|
queryset = self.get_queryset()
|
||||||
try:
|
try:
|
||||||
return queryset.get(**{self.slug_field: data})
|
result = (
|
||||||
except ObjectDoesNotExist:
|
queryset
|
||||||
self.fail('does_not_exist', slug_name=self.slug_field, value=smart_str(data))
|
.filter(**{self.slug_field + "__in": data})
|
||||||
|
.annotate(_slug_field_value=F(self.slug_field))
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
slugs = [item._slug_field_value for item in result]
|
||||||
|
for item in data:
|
||||||
|
if item not in slugs:
|
||||||
|
self.fail('does_not_exist', slug_name=self.slug_field, value=smart_str(item))
|
||||||
|
return result
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
self.fail('invalid')
|
self.fail('invalid')
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
return self.to_many_internal_value([data])[0]
|
||||||
|
|
||||||
def to_representation(self, obj):
|
def to_representation(self, obj):
|
||||||
slug = self.slug_field
|
slug = self.slug_field
|
||||||
if "__" in slug:
|
if "__" in slug:
|
||||||
|
|
|
@ -174,6 +174,12 @@ class SlugForeignKeyTests(TestCase):
|
||||||
]
|
]
|
||||||
assert serializer.data == expected
|
assert serializer.data == expected
|
||||||
|
|
||||||
|
def test_reverse_foreign_key_create_grouped_queries(self):
|
||||||
|
data = {'id': 3, 'name': 'target-3', 'sources': ['source-1', 'source-3']}
|
||||||
|
serializer = ForeignKeyTargetSerializer(data=data)
|
||||||
|
with self.assertNumQueries(1):
|
||||||
|
assert serializer.is_valid()
|
||||||
|
|
||||||
def test_foreign_key_update_with_invalid_null(self):
|
def test_foreign_key_update_with_invalid_null(self):
|
||||||
data = {'id': 1, 'name': 'source-1', 'target': None}
|
data = {'id': 1, 'name': 'source-1', 'target': None}
|
||||||
instance = ForeignKeySource.objects.get(pk=1)
|
instance = ForeignKeySource.objects.get(pk=1)
|
||||||
|
|
|
@ -35,7 +35,7 @@ class MockQueryset:
|
||||||
return list(self.items)
|
return list(self.items)
|
||||||
|
|
||||||
def filter(self, **lookup):
|
def filter(self, **lookup):
|
||||||
return MockQueryset(
|
return MockQueryset([
|
||||||
item
|
item
|
||||||
for item in self.items
|
for item in self.items
|
||||||
if all([
|
if all([
|
||||||
|
@ -44,7 +44,13 @@ class MockQueryset:
|
||||||
else attrgetter(key.replace('__', '.'))(item) == value
|
else attrgetter(key.replace('__', '.'))(item) == value
|
||||||
for key, value in lookup.items()
|
for key, value in lookup.items()
|
||||||
])
|
])
|
||||||
)
|
])
|
||||||
|
|
||||||
|
def annotate(self, **kwargs):
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
for item in self.items:
|
||||||
|
setattr(item, key, attrgetter(value.name.replace('__', '.'))(item))
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class BadType:
|
class BadType:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user