Open antonagestam opened 4 years ago
I absolutely agree!
@antonagestam are you willing to work on this? It would be awesome addition!
@sobolevn Awesome! 👍 I'd be willing to work on this, I'll try to find the time in the coming weeks :)
Very appreciated! 👍
Update: I started working on this but ran into a few issues. I had anticipated that mypy could bind a generic typevar in an outer class using a classvar in a nested class, but that doesn't seem to be the case. Will have to spend some more time to this to see if it can be worked around using a protocol.
As type arguments seem to be the only way to bind type vars I now think this will not be feasible without an upstream change to implement __class_getitem__
. I might create a PR with django-rest-framework to pursuit that.
Done @sobolevn :)
@Goldziher let's add tests as well! This stuff is important!
Sure, but that is a different issue.
Hi there! Is there something I can do to help with this issue? It's not critical to me, but I ran into it and I'd to see Django well typed!
@martinlehoux it is already generic: https://github.com/typeddjango/djangorestframework-stubs/blob/master/rest_framework-stubs/serializers.pyi#L214
But, if you wish to help, then you can add typetests for this feature! 👍 Thanks!
Ok I think I narrowed down what I really wanted to achieve. I guess I expected:
class UserSerializer(ModelSerializer):
class Meta:
model = User
to be enough, that Meta.model would do the typing part for the whole class, but now I'm not so sure it's possible, and I guess I need to do that:
class UserSerializer(ModelSerializer["User"]):
class Meta:
model = User
Have you already thought about this feature? I'm not 100% sure but that's what I can read in the previous comments
I don't think that this is possible 🤔
Because type inference does not work this way in mypy
.
When you specify class UserSerializer(ModelSerializer):
what you really write is class UserSerializer(ModelSerializer[Any]):
And it stops inference from any further steps.
That's the same conclusion I came to as well. Don't know if this would be possible with a plugin, but for me the requirement to specify the model twice is OK.
Perhaps one can use a class decorator that sets the model on Meta and is annotated like model: M -> ModelSerializer[M]
to get rid of the duplication.
One issue I've noticed with the type of ModelSerializer
is that class Meta
is already defined in the type, and you get type errors when you write class Meta:
in serializer files with Pyright in strict mode without # type: ignore
. It should be possible to fix that by defining Meta
with a type annotation instead of with class
.
We currently end up having to add e.g.
assert isinstance(instance, SomeModel)
to update methods. I think it would make sense forModelSerializer
to be defined as approximately:When we narrow the
instance
argument toupdate()
ourselves, we violate LSP becauseupdate()
is defined inBaseSerializer
andinstance
need to accept anyModel
. I think it would be better if that LSP violation was moved into djangorestframework-stubs to paint over the upstream design decision and keeping it from leaking into "user space".