Изменить структуру данных JSON для запроса API POST с помощью Django - PullRequest
1 голос
/ 02 октября 2019

У меня есть конечная точка REST API Django с этой структурой, которую мне нужно опубликовать во внешнем API:

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

Первый элемент в «теле» идет с первым в «заголовке» и «id 'и т. д.

Проблема, с которой я сталкиваюсь, заключается в том, что рассматриваемый API ожидает данные JSON со следующей структурой:

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

И я не могу понять, какпусть моя конечная точка зеркально отобразит эту структуру, сгруппированные вместе bodies, titles и ids, эти группировки вложены в texts и с добавленным в конце параметром language.

Сериализатор, который я использую в моем views.py, выглядит следующим образом:

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

Заранее благодарен за любой совет!

РЕДАКТИРОВАТЬ :

Вот модели:

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)

Ответы [ 2 ]

1 голос
/ 02 октября 2019

Я бы структурировал это так ... (трудно точно знать, не видя моделей и не испытывая их)

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
0 голосов
/ 02 октября 2019

Вы сможете достичь результата, близкого к желаемому, с помощью функции zip и функции карты .

Давайте сделаем это шаг за шагом. Во-первых, вы хотите сжать полученный результат, сгруппировать первое тело с первым заголовком и первым идентификатором, второе со вторым и так далее. Почтовый индекс будет вашим другом здесь. Я назову ваш первый словарь (тот, который содержит все данные) "obj".

>>> zipped_obj = list(zip(obj["body"], obj["title"], obj["id"]))
>>> print(zipped_obj)
[('body1', 'title1', 'id1'), ('body2', 'title2', 'id2'), ('body3', 'title3', 'id3')]

Так что теперь у вас есть то, что вы хотите, но не в структуре, которую вы хотите. Вторым шагом будет превращение его в словарь. Вот где карта будет полезна.

>>> dict_text = ("body", "title", "id")
>>> zipper = lambda x: dict(zip(dict_text, x))
>>> result = list(map(zipper, zipped_obj))
>>> print(result)
[{'body': 'body1', 'title': 'title1', 'id': 'id1'}, {'body': 'body2', 'title': 'title2', 'id': 'id2'}, {'body': 'body3', 'title': 'title3', 'id': 'id3'}]

Теперь у вас должно быть то, что вы хотите. Как уже говорили другие, может быть более эффективный способ сделать это, но это должно ответить на ваш вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...