Я пытаюсь получить значения из модели 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)}]>
Пожалуйста, дайте мне знать, если это правильный способ сделать то, что задумано, и если нет, то что?
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", ...)
Я отредактировал это для вас @AshishTripathi
если вы хотите получить имя пользователя для всех объектов, вам нужно сделать такой запрос
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)
Он говорит, что объект ''QuerySet' не имеет атрибута 'пользователь'`