djangorestframework-stubs icon indicating copy to clipboard operation
djangorestframework-stubs copied to clipboard

Incorrect `instance` type in `ModelSerializer`

Open sobolevn opened this issue 6 years ago • 8 comments

# -*- coding: utf-8 -*-

from rest_framework import serializers

from server.apps.main.models import BlogPost, User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email']


class BlogPostSerializer(serializers.HyperlinkedModelSerializer):
    author = UserSerializer()

    class Meta:
        model = BlogPost
        fields = ['author', 'text', 'is_published', 'created_at']

reveal_type(BlogPostSerializer)

Output:

» PYTHONPATH="$PYTHONPATH:$PWD" mypy server               
server/apps/main/serializers.py:21: note: Revealed type is 'def (instance: Union[Any, None] =, data: Any =, **kwargs: Any) -> server.apps.main.serializers.BlogPostSerializer'

Reproduction: https://github.com/sobolevn/django_stubs_example

It seems like instance should be Optional[BlogPost] in this particular case, not Optional[Any].

sobolevn avatar Aug 25 '19 23:08 sobolevn

It would be great to make ModelSerializers generic. Otherwise, you end up fighting against LSP

linevych avatar Mar 06 '20 12:03 linevych

Should be resolved. @sobolevn

Goldziher avatar Oct 10 '20 11:10 Goldziher

@Goldziher let's write explicit tests for both ModelSerializer and HyperlinkedModelSerializer. Because currently we don't have them: https://github.com/typeddjango/djangorestframework-stubs/blob/master/test-data/typecheck/test_serializers.yml

And close this issue via a PR! 👍

sobolevn avatar Oct 11 '20 08:10 sobolevn

Now that ModelSerializer is generic...what is the syntax to subclass from it?

class ItemSerializer(serializers.ModelSerializer):
                     ^ Missing type parameters for generic type "ModelSerializer" mypy

halfnibble avatar Mar 04 '21 17:03 halfnibble

class​ ​ItemSerializer​(​serializers.ModelSerializer[Item]​):

henribru avatar Mar 04 '21 17:03 henribru

@henribru Thanks for responding! I should have mentioned that I did try that and mypy was happy, but the app crashed with: TypeError: 'SerializerMetaclass' object is not subscriptable

I am using Python 3.7. Do I need to use a newer version of Python? (or perhaps a newer version of DRF?)

halfnibble avatar Mar 04 '21 18:03 halfnibble

You need to use DRF 3.12. If you need to stay on an earlier version you can do this: https://mypy.readthedocs.io/en/stable/runtime_troubles.html#using-classes-that-are-generic-in-stubs-but-not-at-runtime

There's also a workaround using monkeypatch, but I don't know the details of that.

henribru avatar Mar 04 '21 18:03 henribru

@henribru Thank you, SOO MUCH!

Upgrading DRF fixed my SerializerMetaclass type issue, and from the article you linked to, I found that adding from __future__ import annotations to the top of all my Python 3.7 files fixed virtually all of the other typings issues I was having.

I feel like I owe you at least a steak dinner (or the vegetarian equivalent if you don't eat steak...) Do you have a Patreon or PayPal or other way to donate?

halfnibble avatar Mar 04 '21 22:03 halfnibble