Не получать значение других атрибутов, используя select_related в django

Я пытаюсь получить значения из модели TypingTest. Внешний ключ ссылается на модель UserProfile. При извлечении данных я хочу, чтобы имя пользователя также отображалось в результате запроса. Итак, после небольшого исследования я обнаружил, что select_related может быть способом сделать это. Но когда я пытаюсь использовать select_related. Я не вижу имя пользователя, отображается только значение первичного ключа. Это две модели, которые у меня есть.

class UserProfile(models.Model):
   user = models.OneToOneField(User,on_delete=models.CASCADE)
   userName = models.CharField(max_length=26,unique=True)
   email = models.EmailField(max_length=254,unique=True)
   profilePhoto = models.ImageField(default = "/default.png")
   rank = models.CharField(max_length=26,default = "Novice")
   def __str__(self):
       return self.userName
    
class TypingTest(models.Model):
   user = models.ForeignKey(UserProfile,on_delete=models.CASCADE)
   time = models.IntegerField()
   wpm = models.IntegerField()
   accuracy = models.IntegerField()
   raw = models.IntegerField()
   dateTaken = models.DateTimeField(auto_now_add=True)

Соответствующий класс сериализатора:

class TypingTestSerializer(serializers.ModelSerializer):
  class Meta : 
    model = TypingTest
    fields =  ('id','user','time','wpm','accuracy','raw','dateTaken')

class UserSerializer(serializers.ModelSerializer):
   class Meta :
       model = UserProfile
       fields = ('userName','email','profilePhoto','rank')

Это код просмотра, который я написал.

@protected_resource()
@api_view(['GET'])
def getAllTests (request):
    testListQuerySet = models.TypingTest.objects.all()
    selectRelated = models.TypingTest.objects.select_related('user').only("userName")
    print(selectRelated.values())
    serializer=serializers.TypingTestSerializer(models.TypingTest.objects.select_related('user'),many=True)    
    return Response(serializer.data)

Результат, который я получаю:

<QuerySet [{'id': 1, 'user_id': 3, 'time': 60, 'wpm': 60, 'accuracy': 91, 'raw': 79, 'dateTaken': datetime.datetime(2023, 2, 14, 21, 7, 32, 721899, tzinfo=datetime.timezone.utc)}, {'id': 2, 'user_id': 4, 'time': 30, 'wpm': 82, 'accuracy': 99, 'raw': 85, 'dateTaken': datetime.datetime(2023, 2, 14, 21, 33, 45, 326814, tzinfo=datetime.timezone.utc)}]>

Пожалуйста, дайте мне знать, если это правильный способ сделать то, что задумано, и если нет, то что?

Потяните за рычаг выброса энергососущих проектов
Потяните за рычаг выброса энергососущих проектов
На этой неделе моя команда отменила проект, над которым я работал. Неделя усилий пошла насмарку.
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
3
0
62
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Select_related просто извлекает связанные в том же запросе и предотвращает создание нового обращения к БД для доступа к FK. Читайте об этом здесь.

Чтобы получить пользовательские данные, вам не нужно их получать и select_related больше не вызывать попадания в БД. Вы можете получить его, например, таким образом:

user = models.TypingTest.objects.select_related('user').first().user

И если вы хотите представить это в своем ответе, вам нужно добавить user в поля вашего сериализатора:

class TypingTestSerializer(serializers.ModelSerializer):
    class Meta:
        model = TypingTest
        fields = ("user", ...)

Он говорит, что объект ''QuerySet' не имеет атрибута 'пользователь'`

Ashish Tripathi 15.02.2023 11:56

Я отредактировал это для вас @AshishTripathi

Amin 15.02.2023 11:59

Если вы хотите получить имя пользователя для всех объектов, вам нужно сделать такой запрос

TypingTest.objects.select_related('user').values('userName')
Ответ принят как подходящий

Чтобы включить поле userName в вывод, вы должны вместо этого использовать UserSerializer для сериализации связанного объекта UserProfile. В настоящее время вы должны использовать аргумент source, чтобы указать имя связанного поля в модели TypingTest, и UserSerializer для сериализации связанного объекта, поэтому:

class TypingTestSerializer(serializers.ModelSerializer):
    userName = serializers.CharField(source='user.userName')
    
    class Meta: 
        model = TypingTest
        fields =  ('id','user','userName','time','wpm','accuracy','raw','dateTaken')

Затем удалите вызов метода select_related, так как он не нужен:

@protected_resource()
@api_view(['GET'])
def getAllTests (request):
    testListQuerySet = models.TypingTest.objects.all()
    serializer = serializers.TypingTestSerializer(testListQuerySet, many=True)
    return Response(serializer.data)

Другие вопросы по теме