Reputation: 13
I have models:
class Group(models.Model):
number = models.CharField(choices=CLASS_NUMBERS,
max_length=2,
verbose_name="Номер класса")
name = models.CharField(max_length=20,
verbose_name="Название класса")
group_teacher = models.ForeignKey('users.Teacher',
on_delete=models.CASCADE,
verbose_name="Классный руководитель",
related_name='group_teacher')
students = models.ManyToManyField('users.Student',
verbose_name="Ученики", blank=True,
related_name='group_students')
code = models.CharField(max_length=8, unique=True)
class Teacher(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
verbose_name="Преподаватель", related_name='teacher_user')
class Student(models.Model):
user = models.OneToOneField(User,
on_delete=models.CASCADE,
verbose_name="Ученик", related_name='student_user')
and serializers:
class TeacherSerializer(ModelSerializer):
class Meta:
model = Teacher
fields = [
'user'
]
class StudentsSerializer(ModelSerializer):
class Meta:
model = Student
fields = [
'user'
]
class GroupSerializer(ModelSerializer):
class Meta:
model = Group
fields = [
'id',
'number',
'name',
'code',
'group_teacher',
'students',
]
When I make an appeal to the api I get warnings:
Potential n+1 query detected on
Teacher.user
Potential n+1 query detected onTeacher.user
Potential n+1 query detected onStudent.user
Potential n+1 query detected onStudent.user
Potential n+1 query detected onStudent.user
Potential n+1 query detected onStudent.user
my view set:
class GroupModelViewSet(viewsets.ModelViewSet):
serializer_class = GroupSerializer
def get_queryset(self):
return Group.objects.all().prefetch_related('students')
How to fix these errors n+1, select_related does not let me select the model of students and teachers
Upvotes: 1
Views: 633
Reputation: 678
The N+1 query problem happens when the data access framework executed N additional SQL statements to fetch the same data that could have been retrieved when executing the primary SQL query.
You are trying to reach the same database table from all serializers
in your case, this will work
class TeacherSerializer(ModelSerializer):
class Meta:
model = Teacher
fields = "__all__"
class StudentsSerializer(ModelSerializer):
class Meta:
model = Student
fields = "__all__"
class GroupSerializer(ModelSerializer):
class Meta:
model = Group
fields = [
'id',
'number',
'name',
'code',
'group_teacher',
'students',
]
class GroupModelViewSet(viewsets.ModelViewSet):
serializer_class = GroupSerializer
def get_queryset(self):
return Group.objects.all().prefetch_related('group_teacher', 'group_students')
Using the related_name allows you to specify a simpler or more legible name to get the reverse relation. In this case, if you specify user = models.ForeignKey(User, related_name='tech_user')
, the call would then be User.tech_user.all()
prefetch_related('tech_user')
Upvotes: 1