Skip to content

Including lists of resources from non-model annotated objects #704

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

Closed
RobinRamael opened this issue Sep 18, 2019 · 4 comments · Fixed by #868
Closed

Including lists of resources from non-model annotated objects #704

RobinRamael opened this issue Sep 18, 2019 · 4 comments · Fixed by #868
Labels

Comments

@RobinRamael
Copy link

I have a Organization model with a serializer whose instances get some extra data bound to then when using a specific view. this extra data is two lists of Product objects, which is not a django model (just a plain old python object) but its representation should look like a regular relation: the attrs for the organization and then the product lists in included. I tried the following:

class OrganizationSerializer(serializers.ModelSerializer):
    included_serializers = {
        "current_cycle": ProductSerializer,
        "next_cycle": ProductSerializer,
    }

    current_cycle = ResourceRelatedField(
        many=True, read_only=True, model=Product
    )
    next_cycle = ResourceRelatedField(
        many=True, read_only=True, model=Product
    )

    class Meta:
        model = Organization
        fields = ("pk", "current_cycle", "next_cycle")

    class JSONAPIMeta:
        included_resources = ("current_cycle", "next_cycle")

But this results in AttributeError: type object 'Organization' has no attribute 'current_cycle', which happens in utils.get_related_resource_type.

Stepping through the code there, it seems like although it's checking the model attribute directly on the relation, it's not reaching into the child_relation attr when the many is set to True. It does a child attribute which in my case wasn't there although child_relation is.

Doing a quick and dirty fix by including

    elif (
        hasattr(relation, "child_relation")
        and hasattr(relation.child_relation, "model"
    )):
        relation_model = relation.child_relation.model

in the big if/elif/else in get_related_resource_type seems to work. I'm however bery new to this library and maybe I'm just missing something. Otherwise I can make a PR with this fix, of course. Any help would be greatly appreciated :) Thanks!

@RobinRamael RobinRamael changed the title Including lists of resources from annotations Including lists of resources from non-model annotated objects Sep 18, 2019
@sliverc
Copy link
Member

sliverc commented Sep 18, 2019

Not 100% certain about your use case, but usually when using a plain python object the resource name should be defined on the serializer itself.

could be something like this:

class ProductSerializer(Seriaizer):
  ...
  class Meta:
    resource_name = 'products'

Does that work for you or still an exception? If there is still an exception please paste the stack trace.

@sliverc
Copy link
Member

sliverc commented Dec 19, 2019

As there hasn't been any feedback on this I assume this issue has been resolved with above answer and closing this issue therefore. If not please comment.

@sliverc sliverc closed this as completed Dec 19, 2019
@nattyg93
Copy link
Contributor

I think I'm running into this. The issue can be reproduced with:

from uuid import uuid4

from django.db import models
from rest_framework_json_api import serializers, utils


class MyModel(models.Model):
    """My model class."""

    created = models.DateTimeField()

    class JSONAPIMeta:
        """JSON:API meta information."""

        resource_name = "my-models"


class NonModel:
    """Non model class."""

    def __init__(self, *, pk=None, my_models):
        """Initialise the variables."""
        if pk is None:
            pk = str(uuid4())
        self.pk = pk
        self.my_models = my_models


class NonModelSerializer(serializers.Serializer):
    """NonModel serializer."""

    my_models = serializers.ResourceRelatedField(
        model=MyModel, queryset=MyModel.objects.all(), many=True
    )

    class JSONAPIMeta:
        """JSON:API meta information."""

        resource_name = "non-models"

    def create(self, validated_data):
        """Return an instance of NonModel."""
        return NonModel(**validated_data)

Using this serializers results in:

APIException: Could not resolve resource type for relation ManyRelatedField(child_relation=ResourceRelatedField(model=<class 'MyModel'>, queryset=<QuerySet []>))

I've worked around the issue by hacking the model onto the ManyRelatedField by adding the following method to the serializer:

    def get_fields(self):
        """Set model on my_models ManyRelatedField."""
        fields = super().get_fields()
        fields["my_models"].model = fields["my_models"].child_relation.model
        return fields

@sliverc
Copy link
Member

sliverc commented Dec 3, 2020

@nattyg93 Thanks for the example. This could be that this is the issue indeed. I am reopening this issue. PR is welcome.

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

Successfully merging a pull request may close this issue.

3 participants