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

Schema.from_orm not calling resolvers #1364

Open
crbunney opened this issue Dec 17, 2024 · 0 comments
Open

Schema.from_orm not calling resolvers #1364

crbunney opened this issue Dec 17, 2024 · 0 comments

Comments

@crbunney
Copy link

I'm manually serialising a response so that I can modify the contents before returning it. Having read https://django-ninja.dev/guides/response/#serializing-outside-of-views, I'm using the .from_orm method for my Schema, but it doesn't appear to be calling resolvers.

When I return the resulting object from my API method, a ValidationError is thrown because resolved fields are missing.

Context

In my application we have optional features that are configured on a per-customer basis, hence we have some models similar to this:

class Config(django.db.models.Model):
    enable_optional_feature = BooleanField()

class Example(django.db.models.Model):
    field1 = django.db.models.CharField(max_length=100)
    optional_feature = django.db.models.CharField(max_length=100)
    extra_info_a = django.db.models.CharField(max_length=100)
    extra_info_b = django.db.models.CharField(max_length=100)

Example.optional_feature is considered in the disabled state the when Config. enable_optional_feature == False
When Config. enable_optional_feature == True, Example.optional_feature can be set to a string or unset (None).

I've created a schema to return instances of Example:

class ExtraInfoSchema(Schema):
    a: str = Field(alias="extra_info_a")
    b: str = Field(alias="extra_info_b")
    
class ExampleSchema(Schema):
    field1: str
    optional_feature: Optional[str] = None
    extra_info: ExtraInfoSchema

    @staticmethod
    def resolve_extra_info(obj: Example) -> Example:
        return obj

This schema works fine when optional_feature is enabled, but when it's disabled I want to omit it from the response, because from the perspective of the user, it doesn't exist.

You can also see that the response we send presents the information differently to how it's stored in the models. It's the extra_info field that is failing validation. However, when I just return an Example instance, ninja is able to automatically convert it successfully to an ExampleSchema in a way I've not been able to replicate.

What I've tried already

In order to get the response so I can modify it, I've been looking at these pages from the docs:

My API endpoint looks like this:

@router.get(
    "/example/",
    response=ExampleSchema,
)
def example(request: HttpRequest):

    data = ExampleSchema.from_orm(request.user, context={"request":request})

    return data

It successfully returns, but then the ValidationError gets thrown.

I've also been looking through the code, attempting to replicate whatever ninja is doing - because when I just return an Example instance, ninja handles the conversion to an ExampleSchema and there's no ValidationError.
I've been experimenting with bits of code from operation.py without success.

I also tried ninja's JSONRenderer.render, but had similar issues with identifying the correct state and variables it needs to function as expected.

Other thoughts

There may be a better way of approaching this use case of fields that aren't always present, but focussing on manually serialising the object has at least given me something specific to ask about.

It might be possible to handle this by using different schemas depending on whether the optional feature is enabled, but this isn't feasible in reality because we have many optional features leading to lots of possible combinations of optional features.

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

1 participant