django-rest-frameworkmongoenginerestframeworkmongoengine

How to post data to Embedded document with Mongoengine REST


I am trying to use Django with mongoengine to make an API.

So far I can get the objects and delete them. but when I want to post some data. Lets say student + course it is giving an error:

type object 'Course' has no attribute 'objects'

Models en ..

#Model.py


class Course(EmbeddedDocument): 
    course_name = StringField(max_length=200)
    course_fee = StringField(max_length=200)

class Student(Document):
    student_name = StringField(max_length=200)
    student_contactperson = StringField(max_length=200)
    student_adress = StringField(max_length=200)
    courses = ListField(EmbeddedDocumentField(Course))


#Serializers.py
class CourseSerializer(EmbeddedDocumentSerializer):
    class Meta:
        model = Course
        fields = ('course_name','course_fee')


class StudentSerializer(DocumentSerializer):
    courses = CourseSerializer(many=True)
    class Meta:
        model = Student
        fields = ('student_name','student_contactperson','student_adress','courses')
        depth = 2

    def create(self, validated_data):
        course_data = validated_data.pop('courses')
        student = Student.objects.create(**validated_data)
        Course.objects.create(student=student, **course_data)
        return student

#Views.py

class StudentViewSet(meviewsets.ModelViewSet):
    lookup_field = 'name'
    queryset = Student.objects.all().order_by('-date_joined')
    serializer_class = StudentSerializer

Solution

  • A Document represents a MongoDB document (i.e a record in a collection), a Document class is bound to a particular collection. An EmbeddedDocument represents a structure that gets nested in a Document.

    So by design an EmbeddedDocument isn't attached to any collection unless you embed it inside a Document.

    This means that you can't query or save an EmbeddedDocument class, you need to query/save the parent Document.

    Document.objects is an entry point for querying a collection, it only exists on Document classes. You are calling Course.objects.create but Course is an EmbeddedDocument.

    I believe you need to change your code to the following class StudentSerializer(DocumentSerializer): ...

    def create(self, validated_data):
        course_data = validated_data.pop('courses')
        course = Course(**course_data)    # assuming course_data is {course_name: ..., course_fee: ...}
        return Student.objects.create(courses=[course], **validated_data)