Skip to content

Commit

Permalink
Fix Serializer schema generation when used in another serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
arttuperala committed Sep 19, 2023
1 parent e87dff3 commit 6ec9d62
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 8 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ any parts of the framework not mentioned in the documentation should generally b

### Fixed

* Fixed OpenAPI schema generation for `Serializer` children of `ListField`.
* Fixed OpenAPI schema generation for `Serializer` when used inside another `Serializer` or as a child of `ListField`.

## [6.1.0] - 2023-08-25

Expand Down
1 change: 1 addition & 0 deletions example/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,4 @@ class Meta:
"text": "What is the air-speed velocity of an unladen swallow?",
},
]
metadata = {"author": "Bridgekeeper"}
18 changes: 18 additions & 0 deletions example/migrations/0014_questionnaire_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.5 on 2023-09-12 07:12

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("example", "0013_questionnaire"),
]

operations = [
migrations.AddField(
model_name="questionnaire",
name="metadata",
field=models.JSONField(default={}),
preserve_default=False,
),
]
1 change: 1 addition & 0 deletions example/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,4 @@ def __str__(self):
class Questionnaire(models.Model):
name = models.CharField(max_length=100)
questions = models.JSONField()
metadata = models.JSONField()
8 changes: 7 additions & 1 deletion example/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,15 @@ class QuestionSerializer(serializers.Serializer):
required = serializers.BooleanField(default=False)

Check warning on line 430 in example/serializers.py

View check run for this annotation

Codecov / codecov/patch

example/serializers.py#L429-L430

Added lines #L429 - L430 were not covered by tests

class QuestionnaireMetadataSerializer(serializers.Serializer):
author = serializers.CharField()
producer = serializers.CharField(default=None)


class QuestionnaireSerializer(serializers.ModelSerializer):
questions = serializers.ListField(child=QuestionSerializer())
metadata = QuestionnaireMetadataSerializer()

class Meta:

Check warning on line 441 in example/serializers.py

View check run for this annotation

Codecov / codecov/patch

example/serializers.py#L441

Added line #L441 was not covered by tests
model = Questionnaire
fields = "__all__"
fields = ("name", "questions", "metadata")
14 changes: 11 additions & 3 deletions example/tests/test_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def test_schema_id_field():
assert "id" not in company_properties["attributes"]["properties"]


def test_schema_list_of_objects():
"""Schema for ListField child Serializer reflects the actual response structure."""
def test_schema_subserializers():
"""Schema for child Serializers reflects the actual response structure."""
patterns = [
re_path(
"^questionnaires/?$", views.QuestionnaireViewset.as_view({"get": "list"})
Expand All @@ -140,6 +140,14 @@ def test_schema_list_of_objects():
assert {
"type": "object",
"properties": {
"metadata": {
"type": "object",
"properties": {
"author": {"type": "string"},
"producer": {"type": "string"},
},
"required": ["author"],
},
"questions": {
"type": "array",
"items": {
Expand All @@ -153,7 +161,7 @@ def test_schema_list_of_objects():
},
"name": {"type": "string", "maxLength": 100},
},
"required": ["questions", "name"],
"required": ["name", "questions", "metadata"],
} == schema["components"]["schemas"]["Questionnaire"]["properties"]["attributes"]


Expand Down
3 changes: 2 additions & 1 deletion example/tests/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def test_model_serializer_with_implicit_fields(self, comment, client):
assert response.status_code == 200
assert expected == response.json()

def test_model_serializer_with_list_of_objects(self, questionnaire, client):
def test_model_serializer_with_subserializers(self, questionnaire, client):
expected = {
"data": {
"type": "questionnaires",
Expand All @@ -245,6 +245,7 @@ def test_model_serializer_with_list_of_objects(self, questionnaire, client):
"required": False,
},
],
"metadata": {"author": "Bridgekeeper", "producer": None},
},
},
}
Expand Down
7 changes: 5 additions & 2 deletions rest_framework_json_api/schemas/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,9 +681,12 @@ def map_serializer(self, serializer):
and 'links'.
"""
# TODO: remove attributes, etc. for relationshipView??
if isinstance(serializer.parent, serializers.ListField):
if isinstance(
serializer.parent, (serializers.ListField, serializers.BaseSerializer)
):
# Return plain non-JSON:API serializer schema for serializers nested inside
# a ListField, as those don't use the full JSON:API serializer schemas.
# a Serializer or a ListField, as those don't use the full JSON:API
# serializer schemas.
return super().map_serializer(serializer)

required = []
Expand Down

0 comments on commit 6ec9d62

Please sign in to comment.