Search code examples
djangodjango-rest-frameworkswaggerdrf-yasg

Yasg schema generation for nested serializer shows incorrect requests/responses


I have a Django API and I try to create the documentation with drf-yasg. I'm having trouble with the automatically generated schema for my nested serializer and ListAPIview. It looks like this:

serializers.py

class SlideDataSerializer(serializers.ModelSerializer):
    description = SlideDataDescriptionSerializer(many=True, read_only=True, source='slidedatadescription_set')
    class Meta:
        model = SlideData
        fields = ['catch', 'title', 'description', 'icon']


class SlideSerializer(serializers.ModelSerializer):
    datas = SlideDataSerializer(many=True, read_only=True, source='slidedata_set')
    class Meta:
        model = Slide
        fields = ['datas']

class PlanDataDescriptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = PlanDataDescription
        fields = ['description']

class PlanDataSerializer(serializers.ModelSerializer):
    description = PlanDataDescriptionSerializer(many=True, read_only=True, source='plandatadescription_set')
    class Meta:
        model = PlanData
        fields = ['stripColor', 'name', 'description', 'pricePerMonth', 'currency', 'picture']


class PlanSerializer(serializers.ModelSerializer):
    datas = PlanDataSerializer(many=True, read_only=True, source='plandata_set')
    class Meta:
        model = Plan
        fields = ['mainTitle', 'datas']

views.py

class ProjectList(generics.ListAPIView):
    permission_classes = [permissions.AllowAny]
    serializer_class_slide = SlideSerializer
    serializer_class_plan = PlanSerializer

    def get_queryset_object(self, Table, campaign, lang):
        queryset = Table.objects.filter(campaign__name=campaign).filter(language__alpha2=lang)
        return queryset[0]

    def list(self, request):
        Tables = [Slide,
                Plan]


        campaign = self.request.query_params.get('campaign') or "default"
        lang = self.request.query_params.get('lang') or "en"

        if not all(Table.objects.filter(campaign__name=campaign).filter(language__alpha2=lang) for Table in Tables):
            campaign = "default"

        if not all(Table.objects.filter(campaign__name=campaign).filter(language__alpha2=lang) for Table in Tables):
            lang = "en"

        slides = self.serializer_class_slide(self.get_queryset_object(Slide, campaign, lang))
        plans = self.serializer_class_plan(self.get_queryset_object(Plan, campaign, lang))

        return Response({
            "slides": slides.data,
            "plans": plans.data,
        })

and the urls.py:

openapi_info = openapi.Info(
        title="Projectname",
        default_version="v1",
        description="Endpoints",
        terms_of_service="TBD",
        contact=openapi.Contact(email="abc@123.com"),
        license=openapi.License(name="BSD License"),
    )

schema_view = get_schema_view(
    openapi_info,
    public=True,
    permission_classes=(permissions.AllowAny,),
)

API_VERSION = 'v1'
urlpatterns = [
    path('swagger/', schema_view.with_ui(
        'swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('swagger/api.json', schema_view.without_ui( cache_timeout=0), name='schema-swagger-json'),
]

The endpoint is working fine but swagger does not create the right requests or responses and when I access it it gives me this error message:

view's ProjectList raised exception during schema generation; use `getattr(self, 'swagger_fake_view', False)` to detect and short-circuit this
Traceback (most recent call last):
  File "/home/projects/env/lib/python3.8/site-packages/drf_yasg/inspectors/base.py", line 42, in call_view_method
    return view_method()
  File "/home/projects/env/lib/python3.8/site-packages/rest_framework/generics.py", line 108, in get_serializer
    serializer_class = self.get_serializer_class()
  File "/home/projects/env/lib/python3.8/site-packages/rest_framework/generics.py", line 122, in get_serializer_class
    assert self.serializer_class is not None, (
AssertionError: 'ProjectList' should either include a `serializer_class` attribute, or override the `get_serializer_class()` method.

I can not include a serializer class name because I use multiple serializers, I can not create a single serializer for this because they are split up over different models. Overriding the get_serializer_class() has not worked because I don't know how to incorporate these serializers there neither. How could I make this representation work? Thanks in advance


Solution

  • it is because you didn't add your class's Serializer . those serializers you added aren't built in ones . simply add

    serializer_class = SlideSerializer
    

    to your class variables even if you don't want to use that . as in error mentioned , you need to add a serializer_class to your ListAPIView .