Skip to content

Commit 3803e60

Browse files
committed
fix: serialization of non-model dict objects (fixes django-json-api#155 django-json-api#722 django-json-api#1126)
1 parent 735ce29 commit 3803e60

File tree

3 files changed

+40
-4
lines changed

3 files changed

+40
-4
lines changed

rest_framework_json_api/renderers.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,7 @@ def build_json_resource_obj(
459459
resource_name = utils.get_resource_type_from_instance(resource_instance)
460460
resource_data = [
461461
("type", resource_name),
462-
(
463-
"id",
464-
encoding.force_str(resource_instance.pk) if resource_instance else None,
465-
),
462+
("id", utils.get_resource_id_from_instance(resource_instance)),
466463
("attributes", cls.extract_attributes(fields, resource)),
467464
]
468465
relationships = cls.extract_relationships(fields, resource, resource_instance)

rest_framework_json_api/utils.py

+13
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,19 @@ def get_resource_type_from_serializer(serializer):
308308
)
309309

310310

311+
def get_resource_id_from_instance(instance):
312+
"""Returns the resource identifier for a given instance (`id` takes priority over `pk`)."""
313+
if not instance:
314+
return None
315+
elif hasattr(instance, "id"):
316+
return encoding.force_str(instance.id)
317+
elif hasattr(instance, "pk"):
318+
return encoding.force_str(instance.pk)
319+
elif isinstance(instance, dict):
320+
return instance.get("id", instance.get("pk", None))
321+
return None
322+
323+
311324
def get_included_resources(request, serializer=None):
312325
"""Build a list of included resources."""
313326
include_resources_param = request.query_params.get("include") if request else None

tests/test_views.py

+26
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,28 @@ def test_patch(self, client):
183183
}
184184
}
185185

186+
@pytest.mark.urls(__name__)
187+
def test_post_with_missing_id(self, client):
188+
data = {
189+
"data": {
190+
"id": None,
191+
"type": "custom",
192+
"attributes": {"body": "hello"},
193+
}
194+
}
195+
196+
url = reverse("custom")
197+
198+
response = client.post(url, data=data)
199+
assert response.status_code == status.HTTP_200_OK
200+
assert response.json() == {
201+
"data": {
202+
"type": "custom",
203+
"id": None,
204+
"attributes": {"body": "hello"},
205+
}
206+
}
207+
186208

187209
# Routing setup
188210

@@ -211,6 +233,10 @@ def patch(self, request, *args, **kwargs):
211233
serializer = CustomModelSerializer(CustomModel(request.data))
212234
return Response(status=status.HTTP_200_OK, data=serializer.data)
213235

236+
def post(self, request, *args, **kwargs):
237+
serializer = CustomModelSerializer(request.data)
238+
return Response(status=status.HTTP_200_OK, data=serializer.data)
239+
214240

215241
router = SimpleRouter()
216242
router.register(r"basic_models", BasicModelViewSet, basename="basic-model")

0 commit comments

Comments
 (0)