AltSchool / dynamic-rest

Dynamic extensions for Django REST Framework
MIT License
820 stars 107 forks source link

No full route on links response field #343

Open shobu13 opened 1 year ago

shobu13 commented 1 year ago

Hello, according to the default github example, default behavior for many to many relation ship is to give IDs in the corresponding field, and add a route to the details in the links field:

# The Serializer
class UserSerializer(DynamicModelSerializer):
    class Meta:
        model = User
        name = 'user'
        fields = ("id", "name", "location", "groups")

    location = DynamicRelationField('LocationSerializer')
    groups = DynamicRelationField('GroupSerializer', many=True)

# The ViewSet
class UserViewSet(DynamicModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.all()
-->
    GET /users/1/
<--
    200 OK
    {
        "user": {
            "id": 1,
            "name": "John",
            "location": 1,
            "groups": [1, 2],
            "links": {
                "groups": "/users/1/groups"
            }
        }
    }

groups gave IDs [1,2] and you have the root to get more information in the field link>groups as /users/1/groups

But when i setup a basic app:

class Ingredient(models.Model):
    """
    A ingredient that can be a base or and ingredient.
    A base ingredient is the base word you search descriptive for or alts

    Base don't have tag and ingredients can have multiple adjective tags
    """

    class IngredientType(models.IntegerChoices):
        BASE = 0, _('Base')
        INGREDIENT = 1, _('Ingredient')

    name = models.TextField()
    ingredient_type = models.IntegerField(choices=IngredientType.choices)
    tags = models.ManyToManyField(to='core.Tag', related_name='ingredients')
    alts = models.ManyToManyField(to='core.Ingredient', blank=True)

    def __str__(self) -> str:
        return self.IngredientType(self.ingredient_type).label + ': '+ self.name

class Tag(models.Model):
    """
    A tag represent a qualitative of an ingrediant.

    A tag can have multiple ingredients, and an ingredient can have multiple tags.
    """

    name = models.TextField()

    def __str__(self) -> str:
        return self.name

class IngredientSerializer(serializers.DynamicModelSerializer):
    tags = serializers.DynamicRelationField('TagSerializer', many=True, deferred=False)
    alts = serializers.DynamicRelationField('IngredientSerializer', many=True, deferred=False)

    class Meta:
        model = Ingredient
        fields = ('id', 'name', 'ingredient_type', 'tags', 'alts')

class TagSerializer(serializers.DynamicModelSerializer):
    class Meta:
        model = Tag
        fields = ('id', 'name', 'ingredients')

    ingredients = serializers.DynamicRelationField("IngredientSerializer", many=True)
class IngredientViewSet(viewsets.DynamicModelViewSet):
    """
    API endpoint that allows Ingredients to be viewed or edited.
    """
    queryset = Ingredient.objects.all().order_by('name')
    serializer_class = IngredientSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

class TagViewSet(viewsets.DynamicModelViewSet):
    queryset = Tag.objects.all().order_by('name')
    serializer_class = TagSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

i have this result:

-->
    GET /ingredients/1/
<--
{
    "ingredient": {
        "id": 1,
        "name": "armpits",
        "ingredient_type": 0,
        "tags": [
            1,
            2
        ],
        "alts": [],
        "links": {
            "tags": "tags/"
        }
    }
}

Did i've missed something in the doc ?

kieranhood commented 1 year ago

I'm getting the same behaviour. Are there any updates on this?

kieranhood commented 1 year ago

Just taken a closer look at this. In urls.py the viewsets must be registered with the DynamicRouter using register() and register_resource() methods.

I couldn't find this in the docs, so it may be missing from them.