简体   繁体   中英

How to list related objects in Django Rest Framework

I am trying to add a new field in a model serializer which will show all the related values of this model to another.

Like as I have following :

models.py

from django.db import models

class University(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.name

class Student(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    university = models.ForeignKey(University)

    def __unicode__(self):
        return '%s %s' % (self.first_name, self.last_name)

views.py

from rest_framework import viewsets
from .models import University, Student
from .serializers import UniversitySerializer, StudentSerializer

class StudentViewSet(viewsets.ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

class UniversityViewSet(viewsets.ModelViewSet):
    queryset = University.objects.all()
    serializer_class = UniversitySerializer

serializers.py

from rest_framework import serializers
from .models import University, Student

class UniversitySerializer(serializers.ModelSerializer):
    class Meta:
        model = University

class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student

and

urls.py

from rest_framework import routers
from core.views import StudentViewSet, UniversityViewSet
from django.conf import settings
from django.conf.urls import url, include
from django.contrib import admin

router = routers.DefaultRouter()
router.register(r'students', StudentViewSet)
router.register(r'universities', UniversityViewSet)

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('apps.core.urls', namespace='core')),
]

and now i am writing rest-api using django-rest-framework so i get like this

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "students": "http://127.0.0.1:8000/api/students/",
    "universities": "http://127.0.0.1:8000/api/universities/"
}

now when i click http://127.0.0.1:8000/api/universities/ . I get

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "id": 1,
        "name": "test42"
    },
    {
        "id": 2,
        "name": "xxxxxx1222"
    },
    {
        "id": 3,
        "name": "MIT"
    }
] 

and this on clicking http://127.0.0.1:8000/api/students/

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "id": 35,
        "first_name": "Gugu",
        "last_name": "Gaga",
        "university": 11
    },
    {
        "id": 36,
        "first_name": "qwer",
        "last_name": "abcd",
        "university": 12
    }
]

So as student has a particular university no so i want to add a list of ids of students in a university. Like

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "id": 1,
        "name": "test42"
        "students" : {42,56,78}
    },
    {
        "id": 2,
        "name": "xxxxxx1222"
        "students" : {2,6,8}
    },
    {
        "id": 3,
        "name": "MIT"
        "students" : {4,5,7}
    }
] 

How to do that?

You can make use of PrimaryKeyRelatedField for this. First set related_name attribute to your foreign key.

university = models.ForeignKey(University, related_name='students')

And then change your serializer like this.

class UniversitySerializer(serializers.ModelSerializer):
    students = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    class Meta:
        model = University

Hope this helps :)

You can also use the related_name attribute like this (don't forget to makemigrations -> migrate ):

class Student(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    university = models.ForeignKey(University, related_name="students")

Now when accessed in the UniversitySerializer you can just add the new field name:

class UniversitySerializer(serializers.ModelSerializer):
    class Meta:
        model = University
        fields = ("id", "name", "students",)

That will return you exactly what you are asking for, now just to add if you have small data sets and always require to fetch the related data, you can serialize it at the UniversitySerializer level directly (instead of having to make different calls) something like this:

class UniversitySerializer(serializers.ModelSerializer):
    students = StudentSerializer(many=True, read_only=True)
    class Meta:
        model = University
        fields = ("id", "name", "students",)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM