Как я могу структурировать свой ответ JSON, используя сериализатор Django Rest Framework? - PullRequest
4 голосов
/ 30 марта 2019

У меня есть таблица базы данных:

servicenumber | meternumber | usagedatetime | usage
11111         | 22222       | 2019-01-01    | 1.85
11111         | 22222       | 2019-01-02    | 2.25
11111         | 22222       | 2019-01-03    | 1.55
11111         | 22222       | 2019-01-04    | 2.15
11111         | 33333       | 2019-02-01    | 2.95
11111         | 33333       | 2019-02-02    | 3.95
11111         | 33333       | 2019-02-03    | 2.05
11111         | 33333       | 2019-02-04    | 3.22

Как видите, сервисный номер может быть связан с несколькими номерами счетчиков. Думайте о сервисном номере как об уникальном идентификаторе географического местоположения, которое не меняется.

И у меня есть модель Django:

class MeterUsage(models.Model):

    objectid = models.IntegerField(
        db_column='OBJECTID', unique=True, primary_key=True)

    servicenumber = models.IntegerField(
        db_column='serviceNumber', blank=True, null=True)

    meternumber = models.IntegerField(
        db_column='meterNumber', blank=True, null=True)

    usagedatetime = models.DateTimeField(
        db_column='usageDateTime', blank=True, null=True)

    usage = models.DecimalField(
        max_digits=38, decimal_places=8, blank=True, null=True)

А у меня есть базовый сериализатор:

class MeterUsageSerializer(serializers.ModelSerializer):

    class Meta:
        model = MeterUsage
        fields = (
            'usagedatetime',
            'usage'
        )

И текущий ответ:

[
    {
        "usagedatetime": "2019-01-01",
        "usage": "1.85"
    },
    {
        "usagedatetime": "2019-01-02",
        "usage": "2.25"
    },
    {
        "usagedatetime": "2019-01-03",
        "usage": "1.55"
    },

    ....
]

Но то, что я действительно хочу, - это (нужно использовать разделение по номеру счетчика):

[
  {
    "servicenumber": "11111",
    "meternumber": "22222",
    "usagedata": [
      {
        "usagedatetime": "2019-01-01",
        "usage": "1.85"
      },
      {
        "usagedatetime": "2019-01-02",
        "usage": "2.25"
      },
      {
        "usagedatetime": "2019-01-03",
        "usage": "1.55"
      },
      {
        "usagedatetime": "2019-01-04",
        "usage": "2.15"
      },

      ...
    ]
  },
  {
    "servicenumber": "11111",
    "meternumber": "33333",
    "usagedata": [
      {
        "usagedatetime": "2019-02-01",
        "usage": "2.95"
      },
      {
        "usagedatetime": "2019-02-02",
        "usage": "3.95"
      },
      {
        "usagedatetime": "2019-02-03",
        "usage": "2.05"
      },
      {
        "usagedatetime": "2019-02-04",
        "usage": "3.22"
      },

      ...
    ]
  },

  ...
]

Моя конечная цель - отобразить эти данные в виде линейной диаграммы с использованием библиотеки ChartJS в приложении Angular 7, и данные должны быть в следующем формате:

  chartData = [
    {
      label: '22222',
      data: [1.85, 2.25, 1.55, 2.15] 
    },
    { 
      label: '33333',
      data: [2.95, 3.95, 2.05, 3.22]
    }
  ];

Можно ли использовать сериализатор для форматирования данных, как я показал выше? Я пробовал разные методы, основанные на различных уроках, которые я прочитал, но, похоже, ничего не работает, и теперь я просто не понимаю, как с этим справиться.

Любое понимание приветствуется!

Ответы [ 3 ]

2 голосов
/ 02 апреля 2019

Если вы не планируете изменять структуру вашей модели, вы не можете делать то, что хотите, с ModelSerializer .С ModelSerializer вы получаете 1 элемент в результирующем списке для каждой строки базы данных, но вы хотите объединить несколько строк в один элемент в результирующем списке.Однако вы можете попробовать выбрать уникальные пары servicenumner - meternumber и непосредственно подкласс Serializer для сериализации ваших данных.

На ваш взгляд:

queryset = MeterUsage.objects.values('servicenumber', 'meternumber').distinct()
return Response(MeterUsageSerializer(queryset, many=True).data)

И ваш seriliazer:

class MeterUsageSerializer(serializers.Serializer):
    servicenumber = serializers.IntegerField()
    meternumber = serializers.IntegerField()
    usagedata = serializer.SerializerMethodField()

    def get_usagedata(self, obj):
        return [{
            'usagedatetime': item.usagedatetime.strftime('%Y-%m-%d'),
            'usage': item.usage
        } for item in MeterUsage.objects.filter(servicenumber=obj['servicenumber'], meternumber=obj['meternumber'])]

Если вы можете изменить структуру вашей модели, вы можете структурировать свои модели и сериализаторы следующим образом:

class MeterUsage(models.Model):

    objectid = models.IntegerField(
        db_column='OBJECTID', unique=True, primary_key=True)

    servicenumber = models.IntegerField(
        db_column='serviceNumber', blank=True, null=True)

    meternumber = models.IntegerField(
        db_column='meterNumber', blank=True, null=True)

    class Meta:
        unique_together = ('servicenumber', 'meternumber')


class MeterUsageData(models.Model):

    meterusage = models.ForeignKey(MeterUsage, on_delete=models.CASCADE, related_name='data')

    usagedatetime = models.DateTimeField(
        db_column='usageDateTime', blank=True, null=True)

    usage = models.DecimalField(
        max_digits=38, decimal_places=8, blank=True, null=True)

class MeterUsageDataSerializer(serializers.ModelSerializer):
    usagedatetime = serializers.DateTimeField(format=''%Y-%m-%d'')

    class Meta:
        model = MeterUsageData
        fields = ('usagedatetime', 'usage')

class MeterUsageSerializer(serializers.ModelSerializer):
    data = MeterUsageDataSerializer(many=True)

    class Meta:
        model = MeterUsage
        fields = ('servicenumber', 'meternumber', 'data')

С этой моделью - структура сериализаторов, вы можете получитьвыведите в виде:

0 голосов
/ 30 марта 2019

Это просто очень простая задача.Позвольте мне дать вам представление ..

Самый простой способ - создать две таблицы.

Первая (основная) таблица должна содержать информацию о сервисном номере и номере счетчика.Вторая таблица должна быть вложенной таблицей, которая будет содержать информацию об использовании и дате / времени.

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

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

Думайте об этом, так как таблицы Post и комментариев будут генерировать массивы такого типа, в которых Post будет основной таблицей, а Comment - вспомогательной.

Дайте мне знать, что вы чувствуете ..

0 голосов
/ 30 марта 2019

Я не знаю точно, как это сделать, но, может быть, что-то вроде этого:


# assuming you have current_response set to your first data format described in your question

# add "header dict" to every entry in current_response list, save as output

output = [dict() for x in len(current_response)]

for i, entry in current_response:
    output[i] = {
        "servicenumber": "11111",
        "meternumber": i,
        "usagedata": current_response[i],
    }

# create chartData list with dict for every data point containing both meternumber and usagedata

chartData = []

for entry in output:
    data_point = {
        label: entry["meternumber"],
        data: entry["usagedata"]["usage"]
    },
    chartData.append(data_point)

print(chartData)

Будьте осторожны, я не проверял это, так что я не думаю, что это работает, но, возможно, я немного помогу вам, по крайней мере, с концепцией сделать это.

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