django-rest-frameworkdjango-contenttypes

How to POST to a modelViewSet that has a GenericForeignKey?


I have a model that uses the django content type framework

class Foo(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    content_type = models.ForeignKey(ContentType, on_delete=models.PROTECT)
    object_id = models.UUIDField()
    contentObject = GenericForeignKey()

then I use the modelViewSet and the serializer

class FooViewSet(viewsets.ModelViewSet):
    serializer_class = FooSerializer
    queryset = Foo.objects.all()

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo
        fields = ('__all__')

how can I create data using POST to the viewSet? I arbitrary tried POST the object id from another model to content_type, object_id, and content_object then I got the error "Incorrect type. Expected pk value, received str."

I already look in http://www.django-rest-framework.org/api-guide/relations/#generic-relationships or look in stack overflow but can't find any about how to POST the data, maybe my search wasn't thorough enough, I'm sorry. Thanks for checking out my question

UPDATE

I tried to override the create method in serializer: I try to get the ContentType object from get_for_model method, but it return AttributeError: 'AnotherModelX' object has no attribute 'replace'

def create(self, validated_data):
        content_type =  validated_data.get("object_id")
        taggedObject = AnotherObject1.objects.get(id=content_type) if AnotherObject1.objects.filter(id=content_type).count() > 0 else None
        taggedObject = AnotherObject2.objects.get(id=content_type) if AnotherObject2.objects.filter(id=content_type).count() > 0 and taggedObject == None else None

        if taggedObject is not None:
            contentType = ContentType.objects.get_for_model(taggedObject)
            if contentType is not None:
                validated_data["content_type"] = contentType
                validated_data["object_id"] = taggedObject
        return super(FooSerializer, self).create(validated_data)

class Meta:
    model = Foo
    fields = ('__all__')
    extra_kwargs = {
        'content_type': {'required': False},

Solution

  • Turns out my last update was close to the solution, it should be assigning an id in the validated_data["object_id] then it works. Here are the POST json data to Foo:

    {
      "object_id": <<another_model_uuid>>
    }
    

    Be sure to get all the possible model so taggedObject contains the instance of a model.

    It is now solved then, thank you!

    Bellow is the correct create method in serializer

    def create(self, validated_data):
            content_type =  validated_data.get("object_id")
            taggedObject = AnotherObject1.objects.get(id=content_type) if AnotherObject1.objects.filter(id=content_type).count() > 0 else None
            taggedObject = AnotherObject2.objects.get(id=content_type) if AnotherObject2.objects.filter(id=content_type).count() > 0 and taggedObject == None else None
    
            if taggedObject is not None:
                contentType = ContentType.objects.get_for_model(taggedObject)
                if contentType is not None:
                    validated_data["content_type"] = contentType
                    validated_data["object_id"] = taggedObject.id
            return super(FooSerializer, self).create(validated_data)