mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-05-26 01:03:12 +03:00
Use many=True style for pk relations.
This commit is contained in:
parent
b5d8f50f9d
commit
4601487248
|
@ -22,6 +22,9 @@ class RelatedField(WritableField):
|
||||||
"""
|
"""
|
||||||
widget = widgets.Select
|
widget = widgets.Select
|
||||||
many_widget = widgets.SelectMultiple
|
many_widget = widgets.SelectMultiple
|
||||||
|
form_field_class = forms.ChoiceField
|
||||||
|
many_form_field_class = forms.MultipleChoiceField
|
||||||
|
|
||||||
cache_choices = False
|
cache_choices = False
|
||||||
empty_label = None
|
empty_label = None
|
||||||
default_read_only = True # TODO: Remove this
|
default_read_only = True # TODO: Remove this
|
||||||
|
@ -156,7 +159,6 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
Represents a to-one relationship as a pk value.
|
Represents a to-one relationship as a pk value.
|
||||||
"""
|
"""
|
||||||
default_read_only = False
|
default_read_only = False
|
||||||
form_field_class = forms.ChoiceField
|
|
||||||
|
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'does_not_exist': _("Invalid pk '%s' - object does not exist."),
|
'does_not_exist': _("Invalid pk '%s' - object does not exist."),
|
||||||
|
@ -196,85 +198,38 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
raise ValidationError(msg)
|
raise ValidationError(msg)
|
||||||
|
|
||||||
def field_to_native(self, obj, field_name):
|
def field_to_native(self, obj, field_name):
|
||||||
|
if self.many:
|
||||||
|
# To-many relationship
|
||||||
|
try:
|
||||||
|
# Prefer obj.serializable_value for performance reasons
|
||||||
|
queryset = obj.serializable_value(self.source or field_name)
|
||||||
|
except AttributeError:
|
||||||
|
# RelatedManager (reverse relationship)
|
||||||
|
queryset = getattr(obj, self.source or field_name)
|
||||||
|
|
||||||
|
# Forward relationship
|
||||||
|
return [self.to_native(item.pk) for item in queryset.all()]
|
||||||
|
|
||||||
|
# To-one relationship
|
||||||
try:
|
try:
|
||||||
# Prefer obj.serializable_value for performance reasons
|
# Prefer obj.serializable_value for performance reasons
|
||||||
pk = obj.serializable_value(self.source or field_name)
|
pk = obj.serializable_value(self.source or field_name)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# RelatedObject (reverse relationship)
|
# RelatedObject (reverse relationship)
|
||||||
try:
|
try:
|
||||||
obj = getattr(obj, self.source or field_name)
|
pk = getattr(obj, self.source or field_name).pk
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
return None
|
return None
|
||||||
return self.to_native(obj.pk)
|
|
||||||
# Forward relationship
|
# Forward relationship
|
||||||
return self.to_native(pk)
|
return self.to_native(pk)
|
||||||
|
|
||||||
|
|
||||||
class ManyRelatedField(RelatedField):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['many'] = True
|
|
||||||
super(ManyRelatedField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ManyPrimaryKeyRelatedField(ManyRelatedField):
|
|
||||||
"""
|
|
||||||
Represents a to-many relationship as a pk value.
|
|
||||||
"""
|
|
||||||
default_read_only = False
|
|
||||||
form_field_class = forms.MultipleChoiceField
|
|
||||||
|
|
||||||
default_error_messages = {
|
|
||||||
'does_not_exist': _("Invalid pk '%s' - object does not exist."),
|
|
||||||
'incorrect_type': _('Incorrect type. Expected pk value, received %s.'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def prepare_value(self, obj):
|
|
||||||
return self.to_native(obj.pk)
|
|
||||||
|
|
||||||
def label_from_instance(self, obj):
|
|
||||||
"""
|
|
||||||
Return a readable representation for use with eg. select widgets.
|
|
||||||
"""
|
|
||||||
desc = smart_unicode(obj)
|
|
||||||
ident = smart_unicode(self.to_native(obj.pk))
|
|
||||||
if desc == ident:
|
|
||||||
return desc
|
|
||||||
return "%s - %s" % (desc, ident)
|
|
||||||
|
|
||||||
def to_native(self, pk):
|
|
||||||
return pk
|
|
||||||
|
|
||||||
def field_to_native(self, obj, field_name):
|
|
||||||
try:
|
|
||||||
# Prefer obj.serializable_value for performance reasons
|
|
||||||
queryset = obj.serializable_value(self.source or field_name)
|
|
||||||
except AttributeError:
|
|
||||||
# RelatedManager (reverse relationship)
|
|
||||||
queryset = getattr(obj, self.source or field_name)
|
|
||||||
return [self.to_native(item.pk) for item in queryset.all()]
|
|
||||||
# Forward relationship
|
|
||||||
return [self.to_native(item.pk) for item in queryset.all()]
|
|
||||||
|
|
||||||
def from_native(self, data):
|
|
||||||
if self.queryset is None:
|
|
||||||
raise Exception('Writable related fields must include a `queryset` argument')
|
|
||||||
|
|
||||||
try:
|
|
||||||
return self.queryset.get(pk=data)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
msg = self.error_messages['does_not_exist'] % smart_unicode(data)
|
|
||||||
raise ValidationError(msg)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
received = type(data).__name__
|
|
||||||
msg = self.error_messages['incorrect_type'] % received
|
|
||||||
raise ValidationError(msg)
|
|
||||||
|
|
||||||
### Slug relationships
|
### Slug relationships
|
||||||
|
|
||||||
|
|
||||||
class SlugRelatedField(RelatedField):
|
class SlugRelatedField(RelatedField):
|
||||||
default_read_only = False
|
default_read_only = False
|
||||||
form_field_class = forms.ChoiceField
|
|
||||||
|
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'does_not_exist': _("Object with %s=%s does not exist."),
|
'does_not_exist': _("Object with %s=%s does not exist."),
|
||||||
|
@ -313,7 +268,6 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
slug_field = 'slug'
|
slug_field = 'slug'
|
||||||
slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden
|
slug_url_kwarg = None # Defaults to same as `slug_field` unless overridden
|
||||||
default_read_only = False
|
default_read_only = False
|
||||||
form_field_class = forms.ChoiceField
|
|
||||||
|
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'no_match': _('Invalid hyperlink - No URL match'),
|
'no_match': _('Invalid hyperlink - No URL match'),
|
||||||
|
@ -494,8 +448,17 @@ class HyperlinkedIdentityField(Field):
|
||||||
|
|
||||||
### Old-style many classes for backwards compat
|
### Old-style many classes for backwards compat
|
||||||
|
|
||||||
|
class ManyRelatedField(RelatedField):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['many'] = True
|
||||||
|
super(ManyRelatedField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ManyPrimaryKeyRelatedField(PrimaryKeyRelatedField):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
kwargs['many'] = True
|
||||||
|
super(ManyPrimaryKeyRelatedField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ManySlugRelatedField(SlugRelatedField):
|
class ManySlugRelatedField(SlugRelatedField):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
|
@ -332,7 +332,11 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
|
|
||||||
kwargs['label'] = k
|
kwargs['label'] = k
|
||||||
|
|
||||||
fields[k] = v.form_field_class(**kwargs)
|
if getattr(v, 'many', None):
|
||||||
|
fields[k] = v.many_form_field_class(**kwargs)
|
||||||
|
else:
|
||||||
|
fields[k] = v.form_field_class(**kwargs)
|
||||||
|
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
def get_form(self, view, method, request):
|
def get_form(self, view, method, request):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user