Django rest framework Как исправить ошибку many-to-many n+1?
У меня есть модели:
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')
и сериализаторы:
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',
]
Когда я делаю обращение к api, я получаю предупреждения:
Потенциальный запрос n+1 обнаружен на
Teacher.user
Потенциальный запрос n+1 обнаружен наTeacher.user
Потенциальный n+1 запрос обнаружен наStudent.user
Потенциальный n+1 запрос обнаружен наStudent.user
Потенциальный n+1 запрос обнаружен наStudent.user
Потенциальный n+1 запрос обнаружен наStudent.user
мой набор представлений:
class GroupModelViewSet(viewsets.ModelViewSet):
serializer_class = GroupSerializer
def get_queryset(self):
return Group.objects.all().prefetch_related('students')
Как исправить эти ошибки n+1, select_related не дает мне выбрать модель студентов и преподавателей
Проблема N+1 запроса возникает, когда система доступа к данным выполняет N дополнительных SQL-запросов для получения тех же данных, которые могли быть получены при выполнении основного SQL-запроса.
Вы пытаетесь обратиться к одной и той же таблице базы данных из всех сериализаторов
в вашем случае это сработает
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')
Использование related_name позволяет вам указать более простое или более разборчивое имя для получения обратного отношения. В данном случае, если вы укажете user = models.ForeignKey(User, related_name='tech_user')
, вызов будет выглядеть так: User.tech_user.all()
prefetch_related('tech_user')