Home > Net >  How to use prefetch_related in django rest api with foreying key and heritage
How to use prefetch_related in django rest api with foreying key and heritage

Time:05-11

I am working on this Django project, it uses heritage and foreign keys for its models.

These are the models:

class SetorFii(models.Model):
    name = models.CharField(max_length=255)

class Asset(models.Model):
    category = models.ForeignKey(
        Category, related_name='categories', on_delete=models.CASCADE)
    ticker = models.CharField(max_length=255, unique=True)
    price = models.FloatField()

class Fii(Asset):
    setor_fii = models.ForeignKey(
        SetorFii, null=True, default=None, on_delete=models.CASCADE, related_name="setor_fiis")

Class Crypto(Asset):
    circulating_supply = models.FloatField(default=0) 


class PortfolioAsset(models.Model):
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE)

I would like to get the field setor_fii in the PortfolioAssetSerializer, That is what I tried without success.

I get this error message: Cannot find 'setor_fii' on PortfolioAsset object, 'setor_fii' is an invalid parameter to prefetch_related()

Would like some help to achieve that.

The serializer:

class PortfolioAssetSerializer(serializers.ModelSerializer):
    category = serializers.CharField(source='asset.category.name')
    setor_fii = serializers.CharField(source='asset.setor_fii.name')

    class Meta:
        model = models.PortfolioAsset
        fields = (
            'id',
            'category',
            'setor_fii'
        )

The view

class PortfolioAssetList(generics.ListAPIView):
    serializer_class = serializers.PortfolioAssetSerializer

    def get_queryset(self):
        return models.PortfolioAsset.objects.filter(portfolio_id=self.kwargs['pk']).prefetch_related('setor_fii')

CodePudding user response:

To prefetch setor_fii, you will have to go through asset. Since Fii inherits from Asset, Asset will have an automatically created one-to-one field named fii. You can then use that to access setor_fii:

PortfolioAsset.objects.filter(
    portfolio_id=self.kwargs['pk'],
).prefetch_related(
    'asset__fii__setor_fii',
)

Also since the whole relationships here are just one to ones, you can use select_related instead of prefetch_related to get them all in one query (compared to three queries using prefetch_related):

PortfolioAsset.objects.filter(
    portfolio_id=self.kwargs['pk'],
).select_related(
    'asset__fii__setor_fii',
)
  • Related