Fixes #2972: Improve ContentTypeField serializer to elegantly handle invalid data

This commit is contained in:
Jeremy Stretch 2019-03-06 12:42:47 -05:00
parent f35b4bf768
commit ab02f26a0e
2 changed files with 19 additions and 7 deletions

View File

@ -16,6 +16,7 @@ v2.5.8 (FUTURE)
* [#2961](https://github.com/digitalocean/netbox/issues/2961) - Prevent exception when exporting inventory items belonging to unnamed devices * [#2961](https://github.com/digitalocean/netbox/issues/2961) - Prevent exception when exporting inventory items belonging to unnamed devices
* [#2962](https://github.com/digitalocean/netbox/issues/2962) - Increase ExportTemplate `mime_type` field length * [#2962](https://github.com/digitalocean/netbox/issues/2962) - Increase ExportTemplate `mime_type` field length
* [#2966](https://github.com/digitalocean/netbox/issues/2966) - Accept `null` cable length_unit via API * [#2966](https://github.com/digitalocean/netbox/issues/2966) - Accept `null` cable length_unit via API
* [#2972](https://github.com/digitalocean/netbox/issues/2972) - Improve ContentTypeField serializer to elegantly handle invalid data
* [#2976](https://github.com/digitalocean/netbox/issues/2976) - Add delete button to tag view * [#2976](https://github.com/digitalocean/netbox/issues/2976) - Add delete button to tag view
--- ---

View File

@ -8,7 +8,7 @@ from django.db.models import ManyToManyField
from django.http import Http404 from django.http import Http404
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from rest_framework.permissions import BasePermission from rest_framework.permissions import BasePermission
from rest_framework.relations import PrimaryKeyRelatedField from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import Field, ModelSerializer, ValidationError from rest_framework.serializers import Field, ModelSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet as _ModelViewSet, ViewSet from rest_framework.viewsets import ModelViewSet as _ModelViewSet, ViewSet
@ -101,19 +101,30 @@ class ChoiceField(Field):
return data return data
class ContentTypeField(Field): class ContentTypeField(RelatedField):
""" """
Represent a ContentType as '<app_label>.<model>' Represent a ContentType as '<app_label>.<model>'
""" """
def to_representation(self, obj): default_error_messages = {
return "{}.{}".format(obj.app_label, obj.model) "does_not_exist": "Invalid content type: {content_type}",
"invalid": "Invalid value. Specify a content type as '<app_label>.<model_name>'.",
}
# Can't set this as an attribute because it raises an exception when the field is read-only
def get_queryset(self):
return ContentType.objects.all()
def to_internal_value(self, data): def to_internal_value(self, data):
app_label, model = data.split('.')
try: try:
app_label, model = data.split('.')
return ContentType.objects.get_by_natural_key(app_label=app_label, model=model) return ContentType.objects.get_by_natural_key(app_label=app_label, model=model)
except ContentType.DoesNotExist: except ObjectDoesNotExist:
raise ValidationError("Invalid content type") self.fail('does_not_exist', content_type=data)
except (TypeError, ValueError):
self.fail('invalid')
def to_representation(self, obj):
return "{}.{}".format(obj.app_label, obj.model)
class TimeZoneField(Field): class TimeZoneField(Field):