Не получать значение других атрибутов, используя 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 есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
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)

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