DRF: Сериализация с таблицей перекрестных ссылок

У меня есть 3 модели, первая содержит имена контроллеров и их ID, вторая измерения и их ID, а третья имеет внешние ключи к обеим и используется как перекрестная ссылка на основе ID. С помощью следующего сериализатора и представления я могу заставить мой API возвращать измерения, которые есть у каждого контроллера.

Serializer:

class MeasurementsSerializer(serializers.ModelSerializer):
    # used in stationsMeasurementsInfo view
    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

    class Meta:
        model = Measurements
        fields = ['code', 'measurement', 'unit', 'type']

Вид:

class stationsMeasurementsInfo(generics.ListAPIView):
    #returns the measurements a station tracks
    #authentication_classes = (TokenAuthentication,)
    #permission_classes = (IsAuthenticated,)
    serializer_class = MeasurementsSerializer

    def get_queryset(self):
        source = self.kwargs['sourceName']
        name = self.kwargs['stationName']


        final = Measurements.objects.filter(microcontrollersmeasurements__microcontroller__name=name)

        return final

    def list(self, request, *args, **kwargs):
        res = super(stationsMeasurementsInfo, self).list(request, *args, **kwargs)
        res.data = {"source": self.kwargs['sourceName'],
                    "stations": [{
                        "station": self.kwargs['stationName'],
                        "measurements": res.data
                    }
                    ]
                    }
        return res

Проблема в том, что я не могу получить имя контроллера, в настоящее время я вручную вставляю его в список, что означает, что я не могу получить измерения нескольких контроллеров с помощью одного вызова API. Как мне решить эту проблему?

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

Модели:

class Microcontrollers(models.Model):
    name = models.CharField(max_length=25)
    serial_number = models.CharField(max_length=20, blank=True, null=True)
    type = models.CharField(max_length=15, blank=True, null=True)
    software = models.CharField(max_length=20, blank=True, null=True)
    version = models.CharField(max_length=5, blank=True, null=True)
    date_installed = models.DateField(blank=True, null=True)
    date_battery_last_replaced = models.DateField(blank=True, null=True)
    source = models.CharField(max_length=10, blank=True, null=True)
    friendly_name = models.CharField(max_length=45, blank=True, null=True)
    private = models.IntegerField()
    datetime_updated = models.DateTimeField(db_column='DateTime_Updated')  # Field name made lowercase.

    class Meta:
        managed = True
        db_table = 'microcontrollers'
        verbose_name_plural = "Microcontrollers"

    def __str__(self):
        return self.friendly_name

class Measurements(models.Model):
    code = models.CharField(max_length=30)
    measurement = models.CharField(max_length=30)
    unit = models.CharField(max_length=25)
    type = models.CharField(max_length=25)
    datetime_updated = models.DateTimeField(db_column='DateTime_Updated')  # Field name made lowercase.

    class Meta:
        managed = True
        db_table = 'measurements'

    datetime_updated = models.DateTimeField(db_column='DateTime_Updated')  # Field name made lowercase.

class MicrocontrollersMeasurements(models.Model):
    microcontroller = models.ForeignKey(Microcontrollers, models.DO_NOTHING, blank=True, null=True)
    measurement = models.ForeignKey(Measurements, models.DO_NOTHING, blank=True, null=True)
    datetime_updated = models.DateTimeField(db_column='DateTime_Updated')  # Field name made lowercase.

    class Meta:
        managed = True
        db_table = 'microcontrollers_measurements'
    
    def __str__(self):
        return self.measurement.measurement

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

Имена ваших моделей должны быть в единственном числе, например Microcontroller, Measurement,

Если вы все еще хотите остаться с этими отношениями, это решение должно сработать:

Добавьте поле "многие ко многим" к Measurements модели.

microcontrollers = models.ManyToManyField(
    Microcontrollers,
    related_name="measurements",
    through='yourapp.MicrocontrollersMeasurements',
    through_fields=('measurement', 'microcontroller')
)

Обновите свои MeasurementsSerializer

class MeasurementsSerializer(serializers.ModelSerializer):
    ...
   
    microcontrollers = MicrocontrollerSerializer(read_only=True, many=True)
    class Meta:
        model = Measurements
        fields = ['code', 'measurement', 'unit', 'type', 'microcontrollers']

Помните о prefetch_related('microcontrollers') для лучшей производительности запросов к базе данных.

Вернуться на верх