Douglas Xavier
Douglas Xavier

Reputation: 23

Exception Value: type object 'Discipline' has no attribute 'description'

So, I'm building my first Django project using the Django Rest Framework and I have these 3 models on it:

class Student(models.Model):
    user = models.OneToOneField(User, unique=True)
    ra = models.IntegerField()

class Discipline (models.Model):
    description = models.CharField(max_length=150)
    professor = models.ForeignKey(Professor, related_name='disciplines')
    learners = models.ManyToManyField('students.Student', through='enrollments.enrollment', related_name='disciplines')

class Enrollment (models.Model):
    discipline = models.ForeignKey('disciplines.Discipline')
    student = models.ForeignKey(Student)
    enroll_date = models.DateField(auto_now_add=True)

And for these models I've these serializers:

class StudentSerializer (serializers.ModelSerializer):
     ra = serializers.IntegerField(source=Student.ra)
     disciplines = EnrolledDisciplinesSerializer(source="enrollment_set", many=True)
     activities = RealizedActivitiesSerializer(source='activities_set', many=True)

     class Meta:
         model = User
         fields = ('id','username', 'email', 'password', 'ra', 'disciplines','activities')

class DisciplineSerializer (serializers.ModelSerializer):
     professor = serializers.StringRelatedField()
     learners = LearnersSerializer(source="enrollment_set", many=True)

     class Meta:
         model = Discipline
         fields = ('id', 'description', 'professor', 'learners')

class EnrolledDisciplinesSerializer(serializers.ModelSerializer):
     id = serializers.ReadOnlyField(source=Discipline.pk)
     description = serializers.ReadOnlyField(source=Discipline.description)

    class Meta:
        model = Enrollment
        fields = ('id', 'description', 'enroll_date')


class LearnersSerializer(serializers.ModelSerializer):
    id = serializers.ReadOnlyField(source=Student.pk)
    ra = serializers.ReadOnlyField(source=Student.ra)

    class Meta:
        model = Enrollment
        fields = ('id', 'ra', 'enroll_date')

And on my views.py for my students app I've the following code:

class StudentList (generics.ListCreateAPIView):
    model = Student
    serializer_class = StudentSerializer
    permission_classes = [
        permissions.IsAuthenticatedOrReadOnly,
    ]


class StudentDetail (generics.RetrieveAPIView):
    model = Student
    serializer_class = StudentSerializer


class StudentDisciplineList (generics.ListAPIView):
    model = Enrollment
    serializer_class = EnrolledDisciplinesSerializer

    def get_queryset(self):
        queryset = super(StudentDisciplineList, self).get_queryset()
        return queryset.filter(student__pk=self.kwargs.get('pk'))


class StudentActivitiesList (generics.ListAPIView):
    model = Activity
    serializer_class = ActivitiesSerializer

    def get_queryset(self):
        queryset = super(StudentActivitiesList, self).get_queryset()
        return queryset.filter(student__pk=self.kwargs.get('pk'))

After creating the views I added the following to my urls.py file in my students app:

url_patterns = [
    '',
    url(r'^/(?P<pk>\d+)/disciplines$', StudentDisciplineList.as_view(), name='studentdiscipline-list'),
    url(r'^/(?P<pk>\d+)/activities$', StudentActivitiesList.as_view(), name='studentactivities-list'),
    url(r'^/(?P<pk>\d+)$', StudentDetail.as_view(), name='student-detail'),
    url(r'^$', StudentList.as_view(), name='student-list'),
]

Then I added this to my main urls.py file:

import students.urls

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^students/', include(students.urls)),
]

After doing this I went to http://127.0.0.1:8000/students and got the following:

File "C:\Users\Douglas\tg_project\enrollments\serializers.py" in EnrolledDisciplinesSerializer


9.     description = serializers.ReadOnlyField(source=Discipline.description)

Exception Type: AttributeError at /admin
Exception Value: type object 'Discipline' has no attribute 'description'

I've already searched about this on both Google and StackOverflow, but I couldn't find something to help me. I also looked through the entire code to see if I haven't made any typos but it seems that everything is ok.

I'm really thankful for any help to solve this problem.

Upvotes: 2

Views: 370

Answers (1)

knbk
knbk

Reputation: 53679

The source should be a string containing the attributes to get from the Enrollment instance. So in your EnrolledDisciplinesSerializer, for the description, you need 'discipline.description'. discipline (lower-cased) is the attribute name to access the discipline for that enrollment, description the name to get the description for that Discipline instance. Same for the other fields.

Django uses metaclasses to construct models. The way this works, the fields you define in the model don't end up as attributes on the class. That means the Discipline class won't have an attribute Discipline.description. Only instances of Discipline have a description attribute.

Upvotes: 1

Related Questions