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') для лучшей производительности запросов к базе данных.