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)