Я пытаюсь создать вложенный сериализатор UserLoginSerializer
, состоящий из UserSerializer
и NotificationSerializer
, но при попытке сериализации я получаю эту ошибку:
AttributeError: получил AttributeError при попытке получить значение для поле
UserSerializer
. Поле сериализатора может иметь неправильное имя и не соответствовать какому-либо атрибуту или ключу вUserSerializer
экземпляр. Исходный текст исключения был: Объект «UserSerializer» не имеет атрибута «электронная почта».
Вот мои модели.py:
class Notification(models.Model):
kind = models.IntegerField(default=0)
message = models.CharField(max_length=256)
class User(AbstractUser):
username = models.CharField(max_length=150, blank=True, null=True)
email = models.EmailField(unique=True)
customer_id = models.UUIDField(default=uuid.uuid4, editable=False)
И мои сериализаторы.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = [
"id",
"first_name",
"last_name",
"email",
"customer_id"
]
class NotificationSerializer(serializers.ModelSerializer):
class Meta:
model = Notification
fields = [
"id",
"kind",
"message",
]
class UserLoginSerializer(serializers.Serializer):
user_info = UserSerializer(read_only=True)
notifications = NotificationSerializer(many=True, read_only=True)
Ошибка возникает в последней строке этой конечной точки:
def get_login_info(self, request):
notifications = Notification.objects.filter(recipient=request.user)
serializer = UserLoginSerializer(
{
"user_info": UserSerializer(request.user),
"notifications": NotificationSerializer(notifications, many=True),
}
)
return Response(serializer.data)
Что я делаю не так?
Вы можете использовать атрибут .data
.
def get_login_info(self, request):
notifications = Notification.objects.filter(recipient=request.user)
serializer = UserLoginSerializer(
{
"user_info": UserSerializer(request.user).data,
"notifications": NotificationSerializer(notifications, many=True).data,
}
)
return Response(serializer.data)
Вы должны передавать данные, а не сами объекты сериализатора. Аргумент data
позволяет передать словарь данных, который будет использоваться внутренними сериализаторами для создания сериализованного представления. В этом случае вы будете передавать сериализованные данные из UserSerializer
и NotificationSerializer в UserLoginSerializer
, который затем возвращает окончательное сериализованное представление данных.
Или вы можете передать пользователя и уведомления напрямую как таковые:
def get_login_info(self, request):
notifications = Notification.objects.filter(recipient=request.user)
serializer = UserLoginSerializer(
{
"user_info": request.user,
"notifications": notifications
}
)
return Response(serializer.data)
Сериализаторы моделей Django Rest Framework имеют метод to_representation
, который преобразует экземпляры модели в их словарное представление, поэтому в этом случае UserLoginSerializer
будет автоматически использовать UserSerializer
и NotificationSerializer
для сериализации данных пользователя и уведомлений. Вы можете модифицировать/изменить поведение этого метода, переопределив его.
Надеюсь, это поможет.
Второе решение работает. Первый терпит неудачу, потому что вложенные сериализаторы (UserSerializer и NotificationSerializer) на самом деле имеют SerializerMethodFields (которые я не включил в код примера), и они вызываются с ReturnDict() в качестве входных данных вместо требуемых объектов. Таким образом, второе решение охватывает этот случай. Поскольку я не упомянул эти поля SerializerMethodField, я полностью отдаю вам должное за ваш ответ, но я бы предупредил других об этом.