Django prefetch_related на отношении ForeignKey
У меня настроена такая база данных:
class Profile(AbstractBaseUser, PermissionsMixin):
email = models.CharField(max_length=30, null=True, unique=True)
date_created = models.DateTimeField(auto_now=True) ...
class SubProfile(models.Model):
profile = models.OneToOneField(Profile, on_delete=models.CASCADE)
display_name = models.CharField(max_length=25) ...
class SubProfilePost(models.Model):
profile = models.ForeignKey(Profile, related_name='sub_profile_postings', on_delete=models.CASCADE)
title = models.CharField(max_length=20, null=False)
looking_for_date = models.DateTimeField(null=False)
Как мне теперь получить субпрофили и предварительно получить связанные с ними SubProfilePosts?
Я пробовал делать так:
subprofile_queryset = SubProfile.objects \
select_related('profile') \
prefetch_related(
Prefetch('profile__sub_profile_postings', queryset=SubProfilePost.objects.only('id', 'looking_for_date')))
Когда я прогоняю набор queryset через свои сериализаторы:
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
Данные не содержат SubProfilePost(ов). Если я напрямую обращаюсь к obj.profile.sub_profile_postings.all(), я вижу данные.
Возможно, я неправильно понимаю, как работает предварительная выборка, аннотируются ли данные к набору запросов при предварительной выборке и т.д.
Может ли кто-то более опытный просветить меня, если что-то не так с моей установкой, или я неправильно понимаю всю концепцию.
Вот мои сериализаторы:
class ProfileSerializer(ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
extra_kwargs = {
'password': {'write_only': True, 'required': False},
}
class SubProfilePostSerializer(ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = SubProfilePost
fields = '__all__'
class SubProfileSerializer(ModelSerializer):
sub_profile_postings = SubProfilePostSerializer(many=True, read_only=True)
class Meta:
model = SubProfile
fields = [
'id',
'profile',
'display_name',
'sub_profile_postings', # Prefetched field
]
Реализовано с помощью SerializerMethodField.
Я попытался выразить его как Queryset, насколько это возможно, но не смог решить проблему, при которой в подзапрос можно было бы вернуть несколько значений.
class SubProfileSerializer(ModelSerializer):
sub_profile_postings = serializers.SerializerMethodField()
def get_sub_profile_postings(self, obj):
posts = SubProfilePost.objects.filter(profile=obj.profile)
serializer = SubProfilePostSerializer(posts, many=True)
return serializer.data
class Meta:
model = SubProfile
fields = [
'id',
'profile',
'display_name',
'sub_profile_postings', # Prefetched field
]
Попробуйте это
class ProfileSerializer(ModelSerializer):
sub_profile_postings = SubProfilePostSerializer(many=True, read_only=True)
class Meta:
model = Profile
fields = '__all__'
extra_kwargs = {
'password': {'write_only': True, 'required': False},
}
class SubProfilePostSerializer(ModelSerializer):
class Meta:
model = SubProfilePost
fields = '__all__'
class SubProfileSerializer(ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = SubProfile
fields = [
'id',
'profile',
'display_name',
'sub_profile_postings', # Prefetched field
]
Должно получиться что-то вроде этого, просто грубый пример.
{
"id": 23
"profile": {
"id":23224,
"sub_profile_postings": [{}, {}]
}
}
или добавьте геттер в SubProfileSerializer()
, чтобы отфильтровать все SubProfilePost
на основе профиля.