Как я могу присоединить трехмерную таблицу к набору запросов, в котором уже используется select_related?
Я работаю с Django и мне нужно создать API для получения мер в зависимости от типа датчикаs, в зависимости от трех таблиц ( изображение схемы моих таблиц)
- Measures содержит все меры в соответствии с идентификатором датчиков
- Sensors содержит информацию о датчике и тип датчика
- sensor_types содержит информацию о типе (название типа, единица измерения и т.д.)
Мне нужно знать (по крайней мере) имя и ID датчика, тип датчика и меры для датчиков, а также единицы измерения.
Сначала я попытался получить информацию о датчике и тип, к которому принадлежит датчик:
class TypeViewSet(viewsets.ReadOnlyModelViewSet):
"""
API: return the measures of several sensors according to a type of sensors and a date range.
A type is generaly sensors with the same unit (°C, %, kPa)
"""
# See serializers.py
serializer_class = TypesSerializer
def get_queryset(self):
# get the params
idt = self.kwargs['idtype']
# get the date "from"
start = self.request.query_params.get('start')
# get the date "to"
end = self.request.query_params.get('end')
type = SensorTypes.objects.filter(id_sensor_type=idt)
sensors = Sensors.objects.filter(sensor_types_id_sensor_type=idt)\
.select_related('sensor_types_id_sensor_type')
print(sensors.query)
return sensors
Мой файл TypesSerializer выглядит так:
class SensorTypeSerializer(ser.ModelSerializer):
class Meta:
fields = ("id_sensor_type","sensor_type_name","sensor_type_longname","measure_unit")
model = SensorTypes
class TypesSerializer(ser.ModelSerializer):
sensor_types_id_sensor_type=SensorTypeSerializer(
read_only=True
)
#"sensor_type_name", "measure_unit",
class Meta:
fields = ("id_sensor","sensor_name","sensor_types_id_sensor_type")
model = Sensors
и я получил такой результат (вы видите только два датчика, но их больше. ( изображение результата)
Если теперь вы посмотрите на:
{
"id_sensor": 1,
"sensor_name": "b1",
"sensor_types_id_sensor_type": {
"id_sensor_type": 2,
"sensor_type_name": "te",
"sensor_type_longname": "Températures",
"measure_unit": "°C"
}
},
Мне нужно иметь все измерения для этого датчика. (Позже я добавлю диапазон дат)
Моя проблема Я думаю, вы понимаете, что мне нужно, но я не знаю, правильно ли я начал, и я не знаю, как добавить второе присоединение, чтобы получить меры из таблицы Measures.
Я немного запутался, потому что раньше я мог извлекать меры по идентификатору станции следующим образом:
class SensorViewSet(viewsets.ReadOnlyModelViewSet):
"""
API: return the measures of a sensors according to the ID of the sensor and a date range
"""
# See serializers.py
serializer_class = MeasuresSerializer
def get_queryset(self):
#get the params
ids = self.kwargs['idsensor']
# get the date "from"
start = self.request.query_params.get('start')
# get the date "to"
end = self.request.query_params.get('end')
# if param end (from) is empty or does not exist
if end is None or len(end) <= 0:
# Get the last saved measure date/time of a sensor
latest_measure = Measures.objects.filter(sensors_id_sensor=ids).order_by('-measure_created').first()
#save the date
end = latest_measure.measure_created
else:
# get the date from the param end, create an object and save the value to end
end = datetime.strptime(end, '%Y-%m-%d %H:%M:%S')
# if the param start (from) is empty or does not exist
if start is None or len(start) <= 0:
# get the date of the latest measure minus 3 days and save it to start
start = end - timedelta(days=3)
else:
# get the value from the param start, create an object and save it to start
start = datetime.strptime(start, '%Y-%m-%d %H:%M:%S')
# Get all measures from the date range
sensor_measures = Measures.objects \
.filter(sensors_id_sensor=ids,
measure_created__range=[start,end]) \
.order_by('measure_created') \
.select_related('sensors_id_sensor')
#print(sensor_measures)
return sensor_measures
и, как вы видите, сначала я запрашиваю таблицу measures с помощью select_related к таблице Sensors.
Но теперь мне нужно отфильтровать датчики по id типа, и получить информацию о типе как measure_unit
.
Мой вопрос в том, как "включить" таблицу Sensor_types в мой набор запросов?
Айе, я только что понял, что задача немного сложнее.
Мне также нужно отфильтровать датчики станции в соответствии с полем Если вы посмотрите на эту картинку
Вы видите, что существует связь между датчиками и таблицей станций. Таблица Stations содержит поле fields_id_field
, и мне нужно отфильтровать датчики, принадлежащие станции, которая принадлежит выбранному полю.
По этой причине я изменил url реквесты на
http://127.0.0.1:8080/api/map/field/1/type/2/?start=&end=2022-05-21%2010:10:10
мой путь выглядит как
path("field/<int:idfield>/type/<int:idtype>/", TypeViewSet.as_view({'get': 'list'}), name="type_view_set"),
и я получаю значения параметров в следующем виде
idt = self.kwargs['idtype']
idf = self.kwargs['idfield']
Теперь, мой api должен получить меры в соответствии с 4 таблицами
- Measures содержит все меры в соответствии с идентификатором датчиков
- Sensors содержит информацию о датчике и тип датчика
- sensor_types содержит информацию о типе (название типа, единица измерения и т.д.)
- Stations содержит поля_id_field
Я буду очень признателен за помощь, потому что я понятия не имею, как создать набор запросов для 4 таблиц
- таблица Stations необходима для фильтрации набора запросов по полю
- Таблица sensor_types необходима для фильтрации набора запросов по типу
- Таблица Measures нужна для получения всех мер по датчикам (датчик прикреплен к станции)
Большое спасибо за любую помощь, которую вы можете дать мне, чтобы архивировать мою цель!!! Не стесняйтесь спрашивать меня более подробно, если я упустил какую-то информацию, которая может помочь вам лучше понять мой сценарий.
Я решил проблему следующим образом
class TypeViewSet(viewsets.ReadOnlyModelViewSet):
"""
API: return the measures of several sensors according to a type of sensors for a selected field, and a date range.
(A type is generally sensors with the same unit (°C, %, kPa))
The returned value are shorted 1) by stations ASC, then by sensors (ASC) and by date (ASC)
If the time 'end' is empty, the today time will be considered
If the time 'start' is empty, the start time will take the value of the end time, minus 3 days.
Time is UTC zone (Universal Time Coordinated)
"""
# See serializers.py
serializer_class = MeasuresSerializer
def get_queryset(self):
# get the params
idt = self.kwargs['idtype']
idf = self.kwargs['idfield']
# get the date "from"
start = self.request.query_params.get('start')
# get the date "to"
end = self.request.query_params.get('end')
if end is None or len(end) <= 0:
end = datetime.datetime.now()
else:
end = datetime.strptime(end, '%Y-%m-%d %H:%M:%S')
if start is None or len(start) <= 0:
start = end - timedelta(days=3)
else:
start = datetime.strptime(start, '%Y-%m-%d %H:%M:%S')
measures = Measures.objects.filter(
sensors_id_sensor__stations_id_station__fields_id_field=idf,
sensors_id_sensor__sensor_types_id_sensor_type=idt,
sensors_id_sensor__sensor_active=1,
measure_created__range=[start, end]
).order_by(
'sensors_id_sensor__stations_id_station',
'sensors_id_sensor',
'measure_created',
)
#print(measures.query)
return measures
Можно ли было сделать лучше? (если да, то интересно узнать :) )