DRF Depth Only for Specified Fields for GET & POST

So, I have tried this Stack Overflow - Django REST Framework Depth Only For Specified Fields for specifying which field has depth, it's working, but when I want to do POST for insert new record, it can't because it's like django consider my field as required and set it to NULL. Here is my code...

../apps/models.py

class GroupingTypes(models.Model):
    grouping_name = models.CharField(max_length=255, unique=True)
    description = models.TextField(null=True, blank=True)
    
    class Meta:
        db_table = 'grouping_types'

class Templates(models.Model):
    id = models.UUIDField(primary_key=True, default=None, editable=False)
    ...
    name = models.CharField(max_length=255, default=None)
    grouping = models.ForeignKey(GroupingTypes, on_delete=models.CASCADE)
    file = models.FileField(upload_to="templates/")
    ...

    class Meta:
        db_table = 'templates'
    
    def delete(self, *args, **kwargs):
        if self.file and os.path.isfile(self.file.path):
            os.remove(self.file.path)
        super().delete(*args, **kwargs)

../apps/serializers.py

class GroupingTypesSerializer(serializers.ModelSerializer):
    class Meta:
        model = GroupingTypes
        fields = "__all__"


class TemplatesSerializer(serializers.ModelSerializer):
    # Extra fields that's not defined in models
    unix_timestamp_added = serializers.SerializerMethodField()
    datetime_added = serializers.SerializerMethodField()
    
    def get_unix_timestamp_added(self, obj: Templates):
        return int(obj.timestamp_added.timestamp())
    
    def get_datetime_added(self, obj: Templates):
        return obj.timestamp_added.strftime("%Y-%m-%d %H:%M:%S")
    
    grouping = GroupingTypesSerializer(read_only=True)

    class Meta:
        model = Templates
        fields = "__all__"
        extra_kwargs = {
            'file': {'write_only': True}
        }

../apps/views.py

# `../utils/utils.py`
def post(request: HttpRequest, Serializer: serializers.ModelSerializer):
    serializer = Serializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        print(f"\033[92mPOST\033[0m")
        return Response(
            {
                "success": True,
                "msg": "added",
                "data": None,
            },
            status=HTTP_201_CREATED
        )
    print(f"\033[91mPOST\033[0m")
    return Response(
        {
            "success": False, 
            "msg": serializer.errors,
            "data": None,
        },
        status=HTTP_400_BAD_REQUEST
    )

# -------------------------------------------
# views.py
class TemplatesList(APIView):
    def get(self, request: HttpRequest):
        ...
    def post(self. request: HttpRequest):
        return utils.utils.post(request, Serializer=TemplatesSerializer)

../apps/urls.py

urlpatterns = [
    ...
    path("template/", TemplatesList.as_view()),
    path("template/<str:uuid>/", TemplatesDetail.as_view()),
    ...
]

I tried to send POST normally in JSON object format but got error says:

django.db.utils.IntegrityError: null value in column "grouping_id" of relation "templates" violates not-null constraint
DETAIL:  Failing row contains (828b0759-0642-4844-abfa-1b5b602a27d2, ..., TEMPLATE-NAME, null, templates/new-template_OQggWfx.xlsx, ...).

Body post I sent like this. Just normal:

{
    "id": uuid.uuid4(),
    ...,
    "name": "TEMPLATE-NAME",
    "grouping": 2,
    "file": InMemoryUploadedFile,
    ...
}

It's all working normal for GET & POST I remove this line

grouping = GroupingTypesSerializer(read_only=True)

But, it will not output as expected for specify filed depth.

DRF nested serializers are read-only by default as specified here

To make those fields writeable, you have to override the create method in the serializer like this

class TemplatesSerializer(serializers.ModelSerializer):
    # Extra fields that's not defined in models
    unix_timestamp_added = serializers.SerializerMethodField()
    datetime_added = serializers.SerializerMethodField()
    
    def get_unix_timestamp_added(self, obj: Templates):
        return int(obj.timestamp_added.timestamp())
    
    def get_datetime_added(self, obj: Templates):
        return obj.timestamp_added.strftime("%Y-%m-%d %H:%M:%S")
    
    grouping = GroupingTypesSerializer()

    class Meta:
        model = Templates
        fields = "__all__"
        extra_kwargs = {
            'file': {'write_only': True}
        }
    
    def create(self, validated_data):
        grouping_id = validated_data.get("grouping", None)
        if grouping_id:
            validated_data["grouping"] = GroupingTypes.objects.get(id=grouping_id)
        super().create(validated_data)
Back to Top