mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-04 12:30:11 +03:00
Merge e811365593
into 6d4d4dfd04
This commit is contained in:
commit
a6eb94638a
|
@ -315,6 +315,41 @@ class HyperlinkedRelatedField(RelatedField):
|
|||
kwargs = {self.lookup_url_kwarg: lookup_value}
|
||||
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
|
||||
def lookup_parameters(self, data):
|
||||
request = self.context.get('request', None)
|
||||
try:
|
||||
http_prefix = data.startswith(('http:', 'https:'))
|
||||
except AttributeError:
|
||||
self.fail('incorrect_type', data_type=type(data).__name__)
|
||||
|
||||
if http_prefix:
|
||||
# If needed convert absolute URLs to relative path
|
||||
data = urlparse.urlparse(data).path
|
||||
prefix = get_script_prefix()
|
||||
if data.startswith(prefix):
|
||||
data = '/' + data[len(prefix):]
|
||||
|
||||
data = uri_to_iri(data)
|
||||
|
||||
try:
|
||||
match = resolve(data)
|
||||
except Resolver404:
|
||||
self.fail('no_match')
|
||||
|
||||
try:
|
||||
expected_viewname = request.versioning_scheme.get_versioned_viewname(
|
||||
self.view_name, request
|
||||
)
|
||||
except AttributeError:
|
||||
expected_viewname = self.view_name
|
||||
|
||||
if match.view_name != expected_viewname:
|
||||
self.fail('incorrect_match')
|
||||
|
||||
lookup_value = match.kwargs[self.lookup_url_kwarg]
|
||||
lookup_kwargs = {self.lookup_field: lookup_value}
|
||||
return lookup_kwargs
|
||||
|
||||
def to_internal_value(self, data):
|
||||
request = self.context.get('request', None)
|
||||
try:
|
||||
|
@ -461,7 +496,8 @@ class ManyRelatedField(Field):
|
|||
default_empty_html = []
|
||||
default_error_messages = {
|
||||
'not_a_list': _('Expected a list of items but got type "{input_type}".'),
|
||||
'empty': _('This list may not be empty.')
|
||||
'empty': _('This list may not be empty.'),
|
||||
'invalid_values': _('Submitted values invalid')
|
||||
}
|
||||
html_cutoff = None
|
||||
html_cutoff_text = None
|
||||
|
@ -501,6 +537,44 @@ class ManyRelatedField(Field):
|
|||
if not self.allow_empty and len(data) == 0:
|
||||
self.fail('empty')
|
||||
|
||||
# Guard: exit early if no-op
|
||||
if len(data) == 0:
|
||||
return []
|
||||
|
||||
# What would a single lookup for HyperlinkedRelatedField look like?
|
||||
if isinstance(self.child_relation, HyperlinkedRelatedField):
|
||||
|
||||
# Get Lookup parameters
|
||||
lookups = [self.child_relation.lookup_parameters(item) for item in data]
|
||||
if None in lookups:
|
||||
self.fail('invalid_values')
|
||||
|
||||
# 1. Can we just ask for this directly as self.child_relation.lookup_field for all types?
|
||||
lookup_field = list(lookups[0])[0]
|
||||
lookup_values = [item[lookup_field] for item in lookups]
|
||||
lookup_parameters = {
|
||||
lookup_field + '__in': lookup_values
|
||||
}
|
||||
|
||||
# Do the lookup
|
||||
objects = list(self.child_relation.get_queryset().filter(**lookup_parameters))
|
||||
|
||||
# Check we got the result we wanted
|
||||
# This didn't work as types didn't match: set([1, 3]) - set(['1', '3']) == set([1, 3])
|
||||
#
|
||||
# missing_primary_keys = set(getattr(o, lookup_field) for o in objects) - set(lookup_values)
|
||||
# if missing_primary_keys:
|
||||
# self.fail('missing_ids', ids_not_found=list(missing_primary_keys))
|
||||
#
|
||||
# Is there an obvious way to cast to the type of the field?
|
||||
#
|
||||
# So... (Is this sufficient?)
|
||||
if len(set(getattr(o, lookup_field) for o in objects)) != len(set(lookup_values)):
|
||||
self.fail('invalid_values')
|
||||
|
||||
return objects
|
||||
# END
|
||||
|
||||
return [
|
||||
self.child_relation.to_internal_value(item)
|
||||
for item in data
|
||||
|
|
Loading…
Reference in New Issue
Block a user