在django中使用select_related无法获取其他属性的值

ebdffaop  于 2023-02-17  发布在  Go
关注(0)|答案(3)|浏览(167)

我正在尝试从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)}]>

请让我知道这是否是正确的方式做的事情打算,如果不是什么?

eiee3dmh

eiee3dmh1#

要在输出中包含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)
g2ieeal7

g2ieeal72#

如果你想得到所有对象的用户名,那么你必须这样查询

TypingTest.objects.select_related('user').values('userName')
kkbh8khc

kkbh8khc3#

select_related只是为了在同一个查询中提取相关的数据,并防止在访问FK时产生新的DB命中。
要获取用户数据,不需要获取,select_related不会再造成DB命中,可以通过以下方式获取,例如:

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

如果您想在响应中表示它,则必须将user添加到seriliazer字段中:

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

相关问题