0

The code

I have these models :

class Activity(models.Model):
    is_child_friendly = models.BooleanField()
    free_wifi = models.BooleanField()
    parking_avilable = models.BooleanField()

class RouteOrdering(models.Model):
    route_id = models.ForeignKey(Route, on_delete=models.CASCADE)
    activity_id = models.ForeignKey(Activity, on_delete=models.CASCADE, related_name='tracks')
    day = models.IntegerField()
    order = models.IntegerField()

    class Meta:
        ordering = ['order']

And these Serializers:

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity_id','tracks')

The problem

I want the RouteOrderingSerializer to return also the activity with the same activity_id. For this I thought I should use nested serializers.

What I've tried

I've tried adding a nested serializer like so:

activity = ActivitySerializer( read_only=True)

But this resulted no output in the endpoint. I know this is not the use case presented in the documentation, and this is probably why its noy working.

Ill be glad to see what code will work to get this done :)

2 Answers 2

2

I'm not sure why you got an error when you tried the following code. I assumed it was a bug related to the _id ending, but everything works fine when I run it.

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    activity_id = ActivitySerializer( read_only=True)
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity_id','tracks')

While you can, I don't recommend using a name ending in _id for a relation in Django. The issue is that Django internally stores all foreign keys under their <relation_name>_id. This allows various nice things, such as setting <object>.<relation_name>_id to an integer id and saving the object vs setting <object>.<relation_name> to the entire related object (which may require a db lookup to get in the first place). The one place I find this behaviour not intuitive is in serializers, where the default is to represent the relation as "<relation_name>": <id> instead of "<relation_name>_id": <id>, though you can explicitly declare the <relation_name>_id field and either remove or nest the <relation_name> field separately.

If you rename your relations to not have the trailing _id, the following will work:

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    activity = ActivitySerializer( read_only=True)
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity','tracks')

(Note that declaring route instead of route_id would be more in line with the default behaviour, but less clear in my opinion)

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks for trying to help. It didnt work, and returned view without 'activity' field showing up. other ideas?
That is very odd. Can you run it without the activity =... line or the fields =... line and post the resulting json?
here is a pastebin with the resulting json : pastebin.com/MKz4mDKB
Oh, I misread your models. I'm pretty sure you're never supposed to have a relation name ending in _id. Django stores the value internally as <relation_name>_id but abstracts access to the model as just <relation_name>. This can lead to confusing behavior with serializers (since unless you create a nested serializer they return "<relation_name>": <id> instead of "<relation_name>_id": <id>), but that's what Django does.
By the way, any chance there is a possibillity to keep the original 'activity' field (with the id), and to add the new field (with the activity object) in a different name?
|
1

Try this:

class ActivitySerializer(serializers.ModelSerializer):
    class Meta:
        model = Activity

class RouteOrderingSerializer(serializers.ModelSerializer):
    activity_id = ActivitySerializer()
    class Meta:
        model = RouteOrdering
        fields = ('id','day','order','route_id','activity_id')

2 Comments

I get this error: int() argument must be a string, a bytes-like object or a number, not 'collections.OrderedDict', probably because activity_id is suppused to be an int. any ideas?
I can't seem to replicate this error. What Django/Django-Rest-Framework version are you on?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.