Django QuerySet中如何获取ForeignKey名称而非主键值
解决Django QuerySet返回关联对象sensor_name的问题
我正在构建一个复杂的Django QuerySet,需要返回ForeignKey关联的TreeSensor的sensor_name而非主键ID。通过AJAX获取用户输入的实时数据并在DataTable中展示,但当前返回的JSON数据里只有sensor的主键,没有sensor_name。
模型代码
class TreeSensor(models.Model): class Meta: verbose_name_plural = "Tree Sensors" field = models.ForeignKey(Field, on_delete=models.CASCADE) sensor_name = models.CharField(max_length=200, blank=True) datetime = models.DateTimeField(blank=True, null=True, default=now) longitude = models.DecimalField(max_digits=22, decimal_places=16, blank=True, null=True) latitude = models.DecimalField(max_digits=22, decimal_places=16, blank=True, null=True) class TreeSensorMeasurement(models.Model): class Meta: verbose_name_plural = "Tree Sensor Measurements" sensor = models.ForeignKey(TreeSensor, on_delete=models.CASCADE) datetime = models.DateTimeField(blank=True, null=True, default=None) soil_moisture_depth_1 = models.DecimalField(max_digits=15, decimal_places=2) soil_moisture_depth_2 = models.DecimalField(max_digits=15, decimal_places=2) soil_moisture_depth_1_filtered = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True) soil_moisture_depth_2_filtered = models.DecimalField(max_digits=15, decimal_places=2, blank=True, null=True) soil_temperature = models.DecimalField(max_digits=15, decimal_places=2)
视图代码(省略非关键部分)
field_list = Field.objects.filter(user=request.user) tree_sensors = TreeSensor.objects.filter(field_id__in=field_list.values_list('id', flat=True)) statSensors = (TreeSensorMeasurement.objects .filter(sensor_id__in=tree_sensors.values_list('id', flat=True)) .filter(datetime__date__lte=To_T[0]).filter(datetime__date__gte=From_T[0]) .filter(soil_moisture_depth_1__lte=To_T[1]).filter(soil_moisture_depth_1__gte=From_T[1]) .filter(soil_moisture_depth_2__lte=To_T[2]).filter(soil_moisture_depth_2__gte=From_T[2]) .filter(soil_temperature__lte=To_T[3]).filter(soil_temperature__gte=From_T[3]) .order_by('sensor', 'datetime')) TreeData = serializers.serialize('json', statSensors)
前端收到的示例数据
{ "datetime": "2022-11-20T13:28:45.901Z", "sensor": 2, "soil_moisture_depth_1": "166.00", "soil_moisture_depth_1_filtered": "31.00", "soil_moisture_depth_2": "171.00", "soil_moisture_depth_2_filtered": "197.00", "soil_temperature": "11.00" }
解决方案
方法1:使用values()指定字段(简单直接)
修改QuerySet,用values()明确包含需要的字段,包括关联对象的sensor__sensor_name,同时可通过annotate重命名字段:
from django.db.models import F import json statSensors = (TreeSensorMeasurement.objects .select_related('sensor') # 预加载关联对象,避免N+1查询 .filter(sensor_id__in=tree_sensors.values_list('id', flat=True)) .filter(datetime__date__lte=To_T[0]).filter(datetime__date__gte=From_T[0]) .filter(soil_moisture_depth_1__lte=To_T[1]).filter(soil_moisture_depth_1__gte=From_T[1]) .filter(soil_moisture_depth_2__lte=To_T[2]).filter(soil_moisture_depth_2__gte=From_T[2]) .filter(soil_temperature__lte=To_T[3]).filter(soil_temperature__gte=From_T[3]) .order_by('sensor', 'datetime') .annotate(sensor_name=F('sensor__sensor_name')) .values( 'datetime', 'soil_moisture_depth_1', 'soil_moisture_depth_1_filtered', 'soil_moisture_depth_2', 'soil_moisture_depth_2_filtered', 'soil_temperature', 'sensor_name' )) TreeData = json.dumps(list(statSensors))
方法2:自定义序列化逻辑(灵活可控)
如果需要保留模型对象结构,可手动构造返回数据:
import json def serialize_measurements(measurements): data = [] for obj in measurements: item = { 'datetime': obj.datetime.isoformat(), 'sensor': obj.sensor.id, 'sensor_name': obj.sensor.sensor_name, 'soil_moisture_depth_1': str(obj.soil_moisture_depth_1), 'soil_moisture_depth_1_filtered': str(obj.soil_moisture_depth_1_filtered) if obj.soil_moisture_depth_1_filtered else None, 'soil_moisture_depth_2': str(obj.soil_moisture_depth_2), 'soil_moisture_depth_2_filtered': str(obj.soil_moisture_depth_2_filtered) if obj.soil_moisture_depth_2_filtered else None, 'soil_temperature': str(obj.soil_temperature) } data.append(item) return json.dumps(data) # 预加载关联对象优化性能 statSensors = statSensors.select_related('sensor') TreeData = serialize_measurements(statSensors)
内容的提问来源于stack exchange,提问作者user20585556
相关产品推荐
相关产品推荐

