Home > OS >  How to get data from different models in Django Rest-API
How to get data from different models in Django Rest-API

Time:07-06

I have three models, Student, Course and Homework:

What is happening is that I have a front end that the user inputs those fields in ie. all fields from Student, Course and Homework and once those fields are filled out they suppose to click submit to perform CREATE operation. And that's triggers the CreatedData function in views.py.

I have found some relevant examples but still, my serializer is only returning the fields from the Student model for CRUDoperation. I'm not able to get the Course & Homework models fields.

Return different serializer after create() in CreateAPIView in Django REST Framework

Django Rest API. Get all data from different models in a single API call

How to retrieve and create data from model via DJANGO REST API?

how to post multiple model data through one serializer in django rest api

models.py

class Student(models.Model):
    student_id = models.UUIDField(default=uuid.uuid4, unique=True,
                      primary_key=True, editable=False)
    firstName = models.CharField(max_length=20)
    age = models.IntegerField(default=18)

   

class Course(models.Model):
    student_id = models.ForeignKey(Student, on_delete=models.CASCADE)
    courseName = models.CharField(max_length=20)
    courseYear = models.IntegerField(default=2021)
    student = models.ManyToManyField(Student, related_name='courses')


class Homework(models.Model):
    student_id = models.ForeignKey(Student, on_delete=models.CASCADE)

    hwName = models.CharField(max_length=20)
    hwPossScore = models.IntegerField(default=100)
    course = models.ForeignKey(Course, related_name='homeworks', on_delete=models.CASCADE, null=True, blank=True)
    students = models.ManyToManyField(Student)

For these three models I have three serializer classes and combined one to get all data for one API call: Serializers.py

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


class HomeworkSerializer(serializers.ModelSerializer):
   
    class Meta:
        model = Homework
        fields = __all__


class CourseSerializer(serializers.ModelSerializer):
   
    class Meta:
        model = Course
        fields = "__all__"
###I combine both Student and Course into one
class Combined_Serializer(serializers.ModelSerializer):
    
    students = serializers.SerializerMethodField()
    homeworks = serializers.SerializerMethodField()
    courses = serializers.SerializerMethodField()
    
    def get_students(self, obj):
        students = obj.student_set.all()
        serializer = StudentSerializer(students, many=True)
        return serializer.data

    def get_homeworks(self, obj):
        homeworks = obj.homework_set.all()
        serializer = HomeworkSerializer(homeworks, many=True, read_only=True)  
        return serializer.data

    def get_courses(self, obj):
        courses = obj.courses_set.all()
        serializer = CourseSerializer(courses, many=True, read_only=True)  
        return serializer.data

    class Meta:
        model = Student
        fields = ('student_id','firstName','age','homeworks','courses')
   

views.py

 class CreatedData(viewsets.ModelViewSet):

     queryset = Student.objects.all()

     serializer_class = Combined_Serializer


    def create(self, request, pk=None):
       serializer = self.get_serializer(data=request.data) 
       serializer.is_valid(raise_exception=True)
       self.perform_create(serializer)
       headers = self.get_success_headers(serializer.data)
       student_id  = serializer.data['student_id']
       name = serializer.data['Name']        
       student_age = serializer.data['age'] 
       print("SERIALIZER.DATA >" , serializer.data)
       print("HEADERS", headers)

I'm not able to see the Course & Homework models fields when I print serializer.data, only fields from Student models I can get the fields.

I want to design a view which I can access the all fields from all tables. I want to get them after user click submit button.

How to design the view to get that other information in Django rest API?

thanks for your help in advance!

CodePudding user response:

Combined_Serializer returns only the student fields because:

  • model setting: in Meta, model = Student
  • relation: students = obj.student_set.all() <- can you explain how this relation works?

If you have to specify model in the serializer, you can create an abstract model that has foreign key relation to all three models - Student, Course, Homework and modify your serializer accordingly. But it's recommended only if the class will have a solid use and a single responsibility.

class StudentCourseHomework: 
    
```you can name it better with abstract term that explains 
what you want to do with this model```

    student = models.ForeignKey()
    course = models.ForeignKey()
    homework = models.ForeignKey()

    class Meta:
        abstract = True

Alternatives

You can create serializer without model using serializers.Serializer.

class CombinedSerializer(serializers.Serializer):
    class Meta:
        fields = StudentSerializer.Meta.fields
          CoursetSerializer.Meta.fields
          HomeworkSerializer.Meta.fields

Other things

  • removing underscore in class name will be more clean.
  • if you really intend to make serializer that has all three models' fields, it might be better to use a more specific name.
  • Or you can use the view class name like CreateDataSerializer

CodePudding user response:

class CombinedCreateSerializer(serializers.Serializer):
    students = NewStudentSerializer()
    homeworks = NewHomeworkSerializer() # with minimal fields required to create like student_id is not required as it will be obtained later
    courses = NewCourseSerializer() # with minimal fields

    def create(self, validated_data):
        student = Student.objects.create(**validated_data['students'])
        # add student id in courses data
        courses = Course.objects.create(**validated_data['courses'])
        # add student id and course id in homeworks data
        homeworks = Homework.objects.create(**validated_data['homework'])
        return student

In views

class CreatedData(viewsets.ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = Combined_Serializer # your previously defined

    def create(self, request):
       # first verify combined create serializer
       combined_create_serializer = CombinedCreateSerializer(data=request.data) 
       combined_create_serializer.is_valid(raise_exception=True)
       student_instance = self.perform_create(combined_create_serializer)
       combined_serializer_data = self.get_serializer(student_instance) # your final data here which is from previously defined
       # ... rest of your codes

In the past I have achieved doing similar like this; good luck

  • Related