Как получить данные из различных моделей в Django Rest-API
У меня есть три модели, студент, курс и домашнее задание:
Что происходит: у меня есть front end, в котором пользователь вводит эти поля, т.е. все поля из Student
, Course
и Homework
, и после заполнения этих полей он должен нажать submit
для выполнения операции CREATE
. И это запускает функцию CreatedData
в views.py
.
Я нашел несколько подходящих примеров, но все же мой сериализатор возвращает только поля из модели Student
для CRUD
операций. Я не могу получить поля из Course
& Homework
модели.
Возврат другого сериализатора после create() в CreateAPIView в Django REST Framework
Django Rest API. Получите все данные из различных моделей за один вызов API
Как получить и создать данные из модели через DJANGO REST API?
как разместить несколько данных модели через один сериализатор в django rest api
models.py
class Student(models.Model):
student_id = models.UUIDField(default=uuid.uuid4, unique=True,
primary_key=True, editable=False)
firstName = models.CharField(max_length=20)
age = models.IntegerField(default=18)
class Course(models.Model):
student_id = models.ForeignKey(Student, on_delete=models.CASCADE)
courseName = models.CharField(max_length=20)
courseYear = models.IntegerField(default=2021)
student = models.ManyToManyField(Student, related_name='courses')
class Homework(models.Model):
student_id = models.ForeignKey(Student, on_delete=models.CASCADE)
hwName = models.CharField(max_length=20)
hwPossScore = models.IntegerField(default=100)
course = models.ForeignKey(Course, related_name='homeworks', on_delete=models.CASCADE, null=True, blank=True)
students = models.ManyToManyField(Student)
Для этих трех моделей у меня есть три класса сериализаторов, и я объединил один, чтобы получить все данные для одного вызова API: Serializers.py
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = "__all__"
class HomeworkSerializer(serializers.ModelSerializer):
class Meta:
model = Homework
fields = __all__
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = "__all__"
###I combine both Student and Course into one
class Combined_Serializer(serializers.ModelSerializer):
students = serializers.SerializerMethodField()
homeworks = serializers.SerializerMethodField()
courses = serializers.SerializerMethodField()
def get_students(self, obj):
students = obj.student_set.all()
serializer = StudentSerializer(students, many=True)
return serializer.data
def get_homeworks(self, obj):
homeworks = obj.homework_set.all()
serializer = HomeworkSerializer(homeworks, many=True, read_only=True)
return serializer.data
def get_courses(self, obj):
courses = obj.courses_set.all()
serializer = CourseSerializer(courses, many=True, read_only=True)
return serializer.data
class Meta:
model = Student
fields = ('student_id','firstName','age','homeworks','courses')
views.py
class CreatedData(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = Combined_Serializer
def create(self, request, pk=None):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
student_id = serializer.data['student_id']
name = serializer.data['Name']
student_age = serializer.data['age']
print("SERIALIZER.DATA >" , serializer.data)
print("HEADERS", headers)
Я не могу увидеть поля моделей Course
& Homework
при печати serializer.data
, только поля из моделей Student
я могу получить поля.
Я хочу разработать представление, которое может получить доступ ко всем полям из всех таблиц. Я хочу получать их после того, как пользователь нажмет кнопку submit
.
Как разработать представление для получения другой информации в Django rest API?
Заранее спасибо за помощь!
Combined_Serializer
возвращает только поля студента, потому что:
- установка модели: в
Meta
,model = Student
- взаимосвязь:
students = obj.student_set.all()
<- можете ли вы объяснить, как работает это отношение?
Если вам нужноуказывать модель в сериализаторе, вы можете создать абстрактную модель, которая имеет отношение внешнего ключа ко всем трем моделям - Student, Course, Homework и соответствующим образом модифицировать ваш сериализатор. Но это рекомендуется только в том случае, если класс будет иметь сплошное использование и единую ответственность.
class StudentCourseHomework:
```you can name it better with abstract term that explains
what you want to do with this model```
student = models.ForeignKey()
course = models.ForeignKey()
homework = models.ForeignKey()
class Meta:
abstract = True
Альтернативы
Вы можете создать сериализатор без модели, используя serializers.Serializer
.
class CombinedSerializer(serializers.Serializer):
class Meta:
fields = StudentSerializer.Meta.fields
+ CoursetSerializer.Meta.fields
+ HomeworkSerializer.Meta.fields
Другие вещи
- удаление подчеркивания в имени класса будет более чистым.
- если вы действительно собираетесь сделать сериализатор, который имеет поля всех трех моделей, то лучше использовать более конкретное имя.
- Или вы можете использовать имя класса представления, как
CreateDataSerializer
.
class CombinedCreateSerializer(serializers.Serializer):
students = NewStudentSerializer()
homeworks = NewHomeworkSerializer() # with minimal fields required to create like student_id is not required as it will be obtained later
courses = NewCourseSerializer() # with minimal fields
def create(self, validated_data):
student = Student.objects.create(**validated_data['students'])
# add student id in courses data
courses = Course.objects.create(**validated_data['courses'])
# add student id and course id in homeworks data
homeworks = Homework.objects.create(**validated_data['homework'])
return student
По просмотрам
class CreatedData(viewsets.ModelViewSet):
queryset = Student.objects.all()
serializer_class = Combined_Serializer # your previously defined
def create(self, request):
# first verify combined create serializer
combined_create_serializer = CombinedCreateSerializer(data=request.data)
combined_create_serializer.is_valid(raise_exception=True)
student_instance = self.perform_create(combined_create_serializer)
combined_serializer_data = self.get_serializer(student_instance) # your final data here which is from previously defined
# ... rest of your codes
В прошлом я добивался подобных результатов; удачи