from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
from rest_framework.reverse import reverse
from rest_framework.serializers import (
CharField,
HyperlinkedModelSerializer,
HyperlinkedRelatedField,
IntegerField,
Serializer,
SerializerMethodField,
)
[docs]
class GenericHyperlinkedIdentityField(GenericHyperlinkedRelatedField):
def __init__(self, view_name=None, **kwargs):
assert view_name is not None, "The `view_name` argument is required."
kwargs["read_only"] = True
kwargs["source"] = "*"
super().__init__(view_name, **kwargs)
[docs]
class GenericHyperlinkedModelSerializer(HyperlinkedModelSerializer):
serializer_related_field = GenericHyperlinkedRelatedField
serializer_url_field = GenericHyperlinkedIdentityField
[docs]
def serializer_factory(
model, serializer=GenericHyperlinkedModelSerializer, fields="__all__", **kwargs
):
defaultmeta = type(str("Meta"), (object,), {"fields": fields})
meta = getattr(serializer, "Meta", defaultmeta)
meta.model = model
serializer = type(
str("%sModelSerializer" % model._meta.object_name),
(serializer,),
{"Meta": meta},
)
return serializer
[docs]
class ContentTypeInstanceSerializer(Serializer):
id = IntegerField(required=True)
content_type = CharField(required=True)
[docs]
def to_internal_value(self, data):
data = super().to_internal_value(data)
app_label, model = data.get("content_type").split(".")
content_type = get_object_or_404(ContentType, app_label=app_label, model=model)
return get_object_or_404(content_type.model_class(), pk=data.get("id"))
[docs]
class SimpleObjectSerializer(Serializer):
url = GenericHyperlinkedIdentityField(
view_name="apis_core:generic:genericmodelapi-detail"
)
label = SerializerMethodField()
content_type_key = SerializerMethodField()
content_type_name = SerializerMethodField()
[docs]
def get_label(self, obj) -> str:
return str(obj)
[docs]
def get_content_type_key(self, obj) -> str:
content_type = ContentType.objects.get_for_model(obj)
return f"{content_type.app_label}.{content_type.model}"
[docs]
def get_content_type_name(self, obj) -> str:
content_type = ContentType.objects.get_for_model(obj)
return content_type.name