Reputation: 23
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
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