Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolver gets called twice #67

Open
geclick opened this issue Mar 28, 2024 · 4 comments
Open

Resolver gets called twice #67

geclick opened this issue Mar 28, 2024 · 4 comments

Comments

@geclick
Copy link

geclick commented Mar 28, 2024

I am adding a 'user' key to the token claims with the user data including its permissions. Following exactly this I get the tokens with no problem. But resolving the permissions raises a ValidationError, and I realized that the resolver gets called twice:
-first time the obj is a User instance and context is None, so no problem for getting the permission list
-the second time obj is not a User but a ModelAuthReadSchema instance and context is not None but its user is a AnonymousUser, and here comes the errors

this is my schema for User where AuthModel is just get_user_model()

class ModelAuthReadSchema(ModelSchema):
    permissions: List[str] | None

    class Meta:
        model = AuthModel
        fields = ['id', 'username', 'first_name', 'last_name', 'email']

    @staticmethod
    def resolve_permissions(obj, context):
        return get_permissions(obj)

get_permissions is a custom function for getting just business-related permissions

this is the error:

pydantic_core._pydantic_core.ValidationError: 3 validation errors for NinjaResponseSchema
response.refresh
  Field required [type=missing, input_value=<DjangoGetter: LoginInput...', username='cccccc')>, input_type=DjangoGetter]
    For further information visit https://errors.pydantic.dev/2.6/v/missing
response.access
  Field required [type=missing, input_value=<DjangoGetter: LoginInput...', username='cccccc')>, input_type=DjangoGetter]
    For further information visit https://errors.pydantic.dev/2.6/v/missing
response.user
  Field required [type=missing, input_value=<DjangoGetter: LoginInput...', username='cccccc')>, input_type=DjangoGetter]
    For further information visit https://errors.pydantic.dev/2.6/v/missing

this would be the desired output:

{
  "refresh": "xxxxxxxxxxx",
  "access": "yyyyyyyyyyy",
  "user": {
    "permissions": [
      "app_label1.add_model",
      "app_label2.delete_model"
    ],
    "id": 1,
    "username": "ccccccc",
    "first_name": "",
    "last_name": "",
    "email": "[email protected]"
  }
}
@eadwinCode
Copy link
Owner

@geclick Sorry I didn't get notified of this issue on time. I am just seeing it now. I am currently looking into it at the moment

@eadwinCode
Copy link
Owner

@geclick the problem is the resolve_permission method. I don't use the resolver method provided in the Ninja model schema. The problem with that being called twice is likely a problem from pydantic. I know I faced that problem once but I can't remember where.

You can only solve this problem using pydantic model validator at mode='before'. Check the example below.

class ModelAuthReadSchema(ModelSchema):
    permissions: List[str] | None

    class Meta:
        model = AuthModel
        fields = ['id', 'username', 'first_name', 'last_name', 'email']
    
    @model_validator(mode="before")
    def validate_permission_list(cls, values: DjangoGetter) -> typing.Any:
        values = values._obj

        if isinstance(values, dict):
            # values will have ['id', 'username', 'first_name', 'last_name', 'email']
            user = None # add functionality to get the user
            permissions = get_permissions(user)
            values.update(permissions=permissions)
        return values

@geclick
Copy link
Author

geclick commented Apr 8, 2024

@geclick the problem is the resolve_permission method. I don't use the resolver method provided in the Ninja model schema. The problem with that being called twice is likely a problem from pydantic. I know I faced that problem once but I can't remember where.

You can only solve this problem using pydantic model validator at mode='before'. Check the example below.

class ModelAuthReadSchema(ModelSchema):
    permissions: List[str] | None

    class Meta:
        model = AuthModel
        fields = ['id', 'username', 'first_name', 'last_name', 'email']
    
    @model_validator(mode="before")
    def validate_permission_list(cls, values: DjangoGetter) -> typing.Any:
        values = values._obj

        if isinstance(values, dict):
            # values will have ['id', 'username', 'first_name', 'last_name', 'email']
            user = None # add functionality to get the user
            permissions = get_permissions(user)
            values.update(permissions=permissions)
        return values

tnks

@eadwinCode
Copy link
Owner

@geclick can you close this issue if the problem is resolved?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants