#django #api #django-rest-framework #primary-key #django-serializer
Вопрос:
У меня есть представление набора моделей, в котором различные таможенные функции определяются в зависимости от требований. Мне нужно написать другую функцию get, в которой я хочу использовать тот же класс сериализатора. Но поле, которое я определил в классе сериализатора в pkfield, но для функции get, я хочу, чтобы оно было строковым полем, а не полем pk. Как этого добиться??
Кроме того, я определил глубину=1, что также не работает.
class Class(TimeStampAbstractModel): teacher = models.ForeignKey( Teacher, on_delete=models.CASCADE, null=True, related_name="online_class", ) subject = models.ForeignKey( Subject, on_delete=models.SET_NULL, null= True, related_name= "online_class", ) students_in_class = models.ManyToManyField(Student, related_name="online_class")
Мое мнение:
class ClassView(viewsets.ModelViewSet): queryset = Class.objects.all() serializer_class = ClassSerializer serializer_action_classes = { 'add_remove_students': AddStudentstoClassSerializer, 'get_all_students_of_a_class': AddStudentstoClassSerializer, } def get_serializer_class(self): """ returns a serializer class based on the action that has been defined. """ try: return self.serializer_action_classes[self.action] except (KeyError, AttributeError): return super(ClassView, self).get_serializer_class() def add_remove_students(self, request, *args, **kwargs): """ serializer class used is AddStudentstoClassSerializer """ def get_all_students_of_a_class(self,request,pk=None): """ for this I function too, I want to use the same AddStudentstoClassSerializer class but there is a problem. The field students_in_class is already defined as pkfield, whereas I want to use it as a stringfields in the response of this function """"
Мой сериализатор:
class AddStudentstoClassSerializer(serializers.ModelSerializer): students_in_class = serializers.PrimaryKeyRelatedField( many=True, queryset=Student.objects.all() ) class Meta: model = Class fields = ["students_in_class"] depth = 1 def update(self, instance, validated_data): slug = self.context["slug"] stu = validated_data.pop("students_in_class") /................other codes....../ return instance
Здесь мы видим, что класс student_in_class определен как pkfield, что нормально при использовании api обновления, но когда я хочу использовать api get и позвонить get_all_students_of_a_class
, я хочу, чтобы поле было строковым полем или каким-либо другим полем. Как это сделать? Тоже depth= 1
тоже не работает.
Обновить:
Выполните следующие действия, но все еще не работает:
def to_representation(self, instance): rep = super().to_representation(instance) # rep["students_in_class"] = instance.students_in_class rep['students_in_class'] = StudentSerializer(instance.students_in_class).data return rep class StudentSerializer(serializers.ModelSerializer): user = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = Student fields = ['user', 'college_name', 'address']
что я получил в ответе, так это
{ "students_in_class": {} }
это пустой диктант. что нужно сделать!
Ответ №1:
Вы можете переопределить to_representation
свой метод следующим образом.
class AddStudentstoClassSerializer(serializers.ModelSerializer): students_in_class = serializers.PrimaryKeyRelatedField( many=True, queryset=Student.objects.all() ) class Meta: model = Class fields = ["students_in_class"] def to_representation(self, instance): data = { "students_in_class": # Write your logic here } return data def update(self, instance, validated_data): slug = self.context["slug"] stu = validated_data.pop("students_in_class") /................other codes....../ return instance
Комментарии:
1. привет, Хасан, не могли бы вы, пожалуйста, проверить мой обновленный код. это не работает…
2. Измените свою строку на
StudentSerializer(instance.students_in_class.all(), many=True).data
3. да, это сработало идеально, но вместо того, чтобы показывать все поля, могу ли я показывать конкретные поля только для студентов??
4. Вы можете написать новый сиализатор для этого или вот так
instance.students_in_class.all().values('field1', 'field2')
. Вы не будете сериализовываться для этого, если используете 2-й метод.