eadwinCode/django-ninja-jwt

Outdated doc for customized token claim after upgrade to 5.2.10.

mvaled opened this issue · 3 comments

mvaled commented

I'm getting a ValidationError after updating to Pydantic 2.5, django-ninja 1.0.1, django-ninja-extra 0.20.0, django-ninja-jwt 5.2.10.

The error states that no access or refresh token are being given in the result dict:

self = ObtainPairSchema(password='password-140422694852304', username='user-140422694852304')

    def output_schema(self):
        result = self.dict(exclude={"password"})
        result.update(user=UserSchema.from_orm(self._user))
>       return ObtainPairOutputSchema(**result)
E       pydantic_core._pydantic_core.ValidationError: 2 validation errors for ObtainPairOutputSchema
E       refresh
E         Field required [type=missing, input_value=<ninja.schema.DjangoGette...bject at 0x7fb6b49e44c0>, input_type=DjangoGetter]
E           For further information visit https://errors.pydantic.dev/2.5/v/missing
E       access
E         Field required [type=missing, input_value=<ninja.schema.DjangoGette...bject at 0x7fb6b49e44c0>, input_type=DjangoGetter]
E           For further information visit https://errors.pydantic.dev/2.5/v/missing

The code is roughly this.

schema.py:

import typing as t

from ninja import Schema
from ninja_jwt.schema import TokenObtainInputSchemaBase, TokenObtainPairInputSchema


class UserSchema(Schema):
    id: int
    username: str
    is_superuser: bool
    first_name: str | None
    last_name: str | None
    email: str | None


class ObtainPairOutputSchema(Schema):
    refresh: str
    access: str
    user: UserSchema


class ObtainPairBaseSchema(TokenObtainPairInputSchema):
    def output_schema(self):
        result = self.dict(exclude={"password"})
        result.update(user=UserSchema.from_orm(self._user))
        return ObtainPairOutputSchema(**result)


class ObtainPairSchema(ObtainPairBaseSchema):
    pass


class ObtainPairInputSchema(TokenObtainInputSchemaBase):
    @classmethod
    def get_response_schema(cls) -> t.Type[Schema]:
        return ObtainPairOutputSchema

The controller is like:

@api_controller("/token", tags=["token"])
class ObtainPairController(TokenObtainPairController):
    @route.post("/pair", response=ObtainPairOutputSchema, url_name="token_obtain_pair")
    def obtain_token(self, user_token: ObtainPairSchema):
        result = user_token.output_schema()
        if isinstance(user := user_token._user, AbstractBaseUser):
            if not user.is_anonymous and user.is_superuser:
                request: HttpRequest = self.context.request  # type: ignore
                login(request, user)
        return result

and the test that fails is:

class TestJWTLoginv2023(MagicAPITestCase):
    def setUp(self):
        super().setUp()
        User = get_user_model()
        self.username = username = f"user-{id(self)}"
        self.password = password = f"password-{id(self)}"
        self.user = User.objects.create_user(username, password=password)  # type: ignore

    def test_can_obtain_token_for_existing_user(self):
        response = self.client.post(
            "token/pair",
            data={"username": self.username, "password": self.password},
            content_type="application/json",
        )
        self.assertHTTPOk(response)

(The MagicAPITestCase simply takes the version from the name of the class).

In settings.py, I have:

NINJA_JWT = {
   ...
   "TOKEN_OBTAIN_PAIR_INPUT_SCHEMA": "accounts.schema.ObtainPairInputSchema",
   ...
}
mvaled commented

I was looking at the changes and I noticed commit 8187b5a.

So changing the schema from:

class ObtainPairBaseSchema(TokenObtainPairInputSchema):
    def output_schema(self):
        result = self.dict(exclude={"password"})
        result.update(user=UserSchema.from_orm(self._user))
        return ObtainPairOutputSchema(**result)

to:

class ObtainPairBaseSchema(TokenObtainPairInputSchema):
    def output_schema(self):
        result = self.get_response_schema_init_kwargs()
        result.update(user=UserSchema.from_orm(self._user))
        return ObtainPairOutputSchema(**result)

fixes the issue.

Nevertheless, I guess this should be updated in the docs, which still show the previous version:

image

@mvaled thanks I will update the documentation.

This has been resolved. Thanks @mvaled for your help here.