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:
eadwinCode commented
@mvaled thanks I will update the documentation.
eadwinCode commented
This has been resolved. Thanks @mvaled for your help here.