Запрос React не возвращает данные из API Django

Я разрабатываю приложение React, которое извлекает данные о подписчиках пользователя из бэкенд API Django. Однако я столкнулся с проблемой, когда данные о подписчиках возвращаются некорректно.

API Response

Когда я делаю GET-запрос к конечной точке http://127.0.0.1:8000/api/chat/landing/, я получаю JSON-ответ, структурированный следующим образом:

{
    "current_followings": [
        {
            "id": 1,
            "username": "Amir",
            "email": "Amir@amir.ir",
            "full_name": "amirali",
            "profile_photo": "/media/profile_photo/1000_F_244376003_1smlBNfWYSInMDUFymPuCcms6d1mOqaF_oU9kIP0.jpg",
            "banner_photo": "/media/banner_photo/header.jpg",
            "phone": null,
            "address": "",
            "bio": "",
            "profile_views": 1
        }
    ],
    ...
}

Ответ включает массив current_followings, каждый из которых содержит различные поля, такие как id, username, full_name и profile_photo.

Django views.py

Представление, которое обрабатывает этот запрос, определено следующим образом:

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from .models import Follower, BasicUserProfile  # Assuming these are defined elsewhere

class ChatLandingView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            current_basic_user_profile = get_current_user_profile(request, User, BasicUserProfile)
            current_followings = Follower.objects.filter(follower=current_basic_user_profile).select_related('following')

            followings_serializer = BasicUserProfileSerializer([f.following for f in current_followings], many=True)

            data = {
                "current_followings": followings_serializer.data,
                ...
            }

            return Response(data, status=status.HTTP_200_OK)

        except ObjectDoesNotExist:
            return Response({"error": "Object not found"}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

Это представление проверяет наличие аутентифицированных пользователей и извлекает данные об их следовании, используя модель Follower. Оно сериализует данные следования перед отправкой их обратно в ответ.

Код реакции

В моем компоненте React я использую React Query для получения следующих данных:

import React from 'react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

const getToken = () => localStorage.getItem('authToken');

const fetchFollowings = async () => {
    const token = getToken();
    if (!token) {
        throw new Error("No authentication token found. Please log in.");
    }

    const response = await axios.get('http://127.0.0.1:8000/api/chat/landing/', {
        headers: { 'Authorization': `Bearer ${token}` },
    });

    return response.data.current_followings;
};

const ChatLanding = () => {
    const { data: followings = [], error, isLoading } = useQuery({
        queryKey: ['followings'],
        queryFn: fetchFollowings,
    });

    return (
        <div>
            <h2>Your Followings</h2>
            {isLoading && <p>Loading...</p>}
            {error && <p>{error.message}</p>}
            {followings.length === 0 && !isLoading && !error && (
                <p>No followings found.</p>
            )}
            {followings.length > 0 && (
                <ul>
                    {followings.map(following => (
                        <li key={following.id}>
                            <img src={following.profile_photo} alt={following.full_name} />
                            <p>{following.full_name} ({following.username})</p>
                        </li>
                    ))}
                </ul>
            )}
        </div>
    );
};

export default ChatLanding;

Выпуск

  • Массив current_followings не отображается корректно в моем компоненте React. Вместо этого я иногда получаю ошибку, связанную с маркером аутентификации.
  • Я проверил, что токен правильно хранится и извлекается в коде на стороне клиента.
  • Когда я проверяю консоль, я вижу, что ответ API успешно возвращается со статусом 200.

Вопрос

Что может быть причиной того, что представление не отображается так, как ожидалось? Есть ли какие-либо изменения, которые я должен внести в представление Django или в код React, чтобы решить эту проблему?

Любые соображения будут высоко оценены!

Токен хранится правильно и правильно прикрепляется к заголовкам. Вам не хватает authentication_classes в представлении:

views.py

class ChatLandingView(APIView):
    authentication_classes = [TokenAuthentication]
    ...

Хотя я не уверен, какой пакет аутентификации у вас установлен. Просто убедитесь, что префикс Authentication также корректен.

Проблема была вызвана неправильным использованием сериализатора для данных current_followings. В исходном коде сериализатор был неправильно применен к списку объектов BasicUserProfile, что вызывало проблемы при попытке вернуть в ответ список следования.

Вот как была решена эта проблема:

  1. Корректная обработка current_followings: Переменная current_followings была получена с помощью Follower.objects.filter(follower=current_basic_user_profile), но перед возвратом данные нужно было правильно сериализовать. Вместо того чтобы сериализовать весь объект Follower, нам нужно было сериализовать поле following, содержащее профили пользователей, за которыми ведется наблюдение.

  2. Правильное использование select_related: Для оптимизации запроса в поле select_related было использовано following, чтобы избежать дополнительных запросов к базе данных при обращении к связанным профилям пользователей. Это гарантирует, что профили пользователей following будут получены вместе с объектом Follower, что повышает производительность.

  3. Обновленное приложение сериализатора: Сериализатор BasicUserProfileSerializer правильно использовался для сериализации following профилей пользователей, а не для сериализации самой Follower модели.

Обновленный код:

class ChatLandingView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        try:
            current_basic_user = get_current_user(request, User)
            current_basic_user_profile = get_current_user_profile(request, User, BasicUserProfile)
            topics_to_follow = get_topics_to_follow(Topic, ObjectDoesNotExist, random)
            who_to_follow = get_who_to_follow(BasicUserProfile)

            # Adjusted field names based on your Follower model
            current_followings = Follower.objects.filter(follower=current_basic_user_profile).select_related('following')

            # Serialize the data
            user_serializer = BasicUserProfileSerializer(current_basic_user_profile)
            topics_serializer = TopicSerializer(topics_to_follow, many=True)
            followings_serializer = BasicUserProfileSerializer([f.following for f in current_followings], many=True)
            who_to_follow_serializer = BasicUserProfileSerializer(who_to_follow, many=True)

            data = {
                "current_basic_user": user_serializer.data,
                "current_basic_user_profile": user_serializer.data,
                "who_to_follow": who_to_follow_serializer.data,
                "topics_to_follow": topics_serializer.data,
                "current_followings": followings_serializer.data,
            }

            return Response(data, status=status.HTTP_200_OK)

        except ObjectDoesNotExist:
            return Response({"error": "Object not found"}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

Ключевые исправления:

  1. Сериализация following профилей:

    • Вместо того чтобы сериализовать объект Follower, мы сериализовали поле following (f.following), которое является фактическим профилем пользователя, за которым ведется наблюдение.
    • Это делается с помощью строки:
      followings_serializer = BasicUserProfileSerializer([f.following for f in current_followings], many=True)
      
  2. Оптимизация запросов к базе данных с помощью select_related:

    • В запросе используется select_related('following'), чтобы получить following профили пользователей в том же запросе к базе данных, обеспечивая эффективный доступ к связанным данным о пользователях.

Результат:

Обновленный код корректно возвращает список профилей пользователей, за которыми следит текущий пользователь. Поле current_followings теперь возвращает сериализованные данные пользователей, за которыми следят, а структура ответа отформатирована соответствующим образом.

Вернуться на верх