kh_one
kh_one

Reputation: 257

Change structure of JSON data for API POST request with Django

I have a Django REST API endpoint with this structure, that I need to post to an external API:

{
    "body": [
        "...",
        "...",
        "...",
    ],
    "title": [
        "...",
        "...",
        "...",
    ],
    "id": [
        "...",
        "...",
        "...",
    ]
}

The first item under 'body' goes with the first under 'title' and 'id', and so forth.

The problem I'm having is that the API in question expects JSON data with the following structure:

{
  "texts": [
    {
      "body": "...",
      "title": "...",
      "id": "..."
    },
    {
      "body": "...",
      "title": "...",
      "id": "..."
    },
    {
      "body": "...",
      "title": "...",
      "id": "..."
    },
  ],
  "language": "EN",
}

And I can't figure out how have my endpoint mirror that structure, with the bodies, titles, and ids grouped together, those groupings nested under texts, and with the language parameter appended at the end.

The serializer I'm using in my views.py looks as follows:

class MyReasonsSerializer(serializers.Serializer):
    body = serializers.SerializerMethodField()
    title = serializers.SerializerMethodField()
    id = serializers.SerializerMethodField()

    def get_body(self, obj):
        return obj.reasons.order_by('transaction_date').values_list('body', flat=True)

    def get_title(self, obj):
        return obj.reasons.order_by('transaction_date').values_list('title', flat=True)

    def get_id(self, obj):
        return obj.reasons.order_by('transaction_date').values_list('transaction_date', flat=True)

class ReasonsData(RetrieveAPIView):
    queryset = Market.objects.all().prefetch_related('reasons')
    authentication_classes = []
    permission_classes = []
    serializer_class = MyReasonsSerializer

Thanks in advance for any advice!

EDIT:

Here are the models:

class Market(models.Model):
    title = models.CharField(max_length=50, default="")
    current_price = models.DecimalField(max_digits=5, decimal_places=2, default=0.50)
    description = models.TextField(default="")
    ...
    language = models.CharField(max_length=2, default="EN")

    def __str__(self):
        return self.title[:50]

class Reason(models.Model):
    user_id = models.ForeignKey('users.CustomUser',
        on_delete=models.CASCADE,
        related_name='user_reasons',
        default=None)
    market = models.ForeignKey(
        Market,
        on_delete=models.CASCADE,
        related_name='reasons',
        default=None)
    ...
    valence = models.CharField(max_length=11, default="")
    title = models.TextField(default="")
    body = models.TextField(default="")

    def __str__(self):
        return str(self.title)

Upvotes: 1

Views: 303

Answers (1)

Carl
Carl

Reputation: 851

I would structure it like this... (its hard to know exactly without seeing the models and trying it out)

class ReasonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Reason
        fields = ("id", "body", "title")

class MarketSerializer(serializers.Serializer):
    texts = ReasonSerializer(many=True, source="reasons")
    language = serializers.CharField()

    class Meta:
        model = Market

class ReasonsData(RetrieveAPIView):
    queryset = Market.objects.all()
    authentication_classes = []
    permission_classes = []
    serializer_class = MarketSerializer

    def get_queryset(self):
        qs = super().get_queryset()

        # filter queryset by valence if passed as a query param
        # ?valence=something
        valence = self.request.query_params.get("valence", None)
        if valence is not None:
            qs = qs.filter(reasons__valence=valence)

        return qs

Upvotes: 1

Related Questions