视图中的select_related没有减少Django中具有混合属性的查询

1l5u6lss  于 2023-05-08  发布在  Go
关注(0)|答案(1)|浏览(117)

我已经包含了select_related,总体上减少了查询和预取数据的数量。但是,我有一个单独查询的案例。我不确定我是否在期待一种不可能的行为。
我有以下看法:
list.py (查看)我在其中使用select_related

class OpportunitiesList(generics.ListAPIView):
    serializer_class = OpportunityGetSerializer

    def get_queryset(self):
        queryset = Opportunity.objects.all()
        queryset = queryset.filter(deleted=False)

        return queryset.select_related('nearest_airport').order_by('id')

模型中有四个对象:opportunity.py(型号):

class Opportunity(models.Model):
    deleted = models.BooleanField(
        default=False,
    )
    opportunity_name = models.TextField(blank=True, null=True)
    nearest_airport = models.ForeignKey(AirportDistance,
                                        on_delete=models.SET_NULL,
                                        db_column="nearest_airport",
                                        null=True)
class AirportDistance(models.Model):
    airport_id = models.ForeignKey(Airport,
                                   on_delete=models.SET_NULL,
                                   db_column="airport_id",
                                   null=True)
    airport_distance = models.DecimalField(max_digits=16, decimal_places=4, blank=False, null=False)

    @property
    def airport_name(self):
        return self.airport_id.name

location_assets.py(Model):

class Location(models.Model):
    name = models.CharField(null=True, blank=True, max_length=255)
    location_fuzzy = models.BooleanField(
        default=False,
        help_text=
        "This field should be set to True if the `point` field was not present in the original dataset "
        "and is inferred or approximated by other fields.",
    )
    location_type = models.CharField(null=True, blank=True, max_length=255)
    
    
class Airport(Location):
    description = models.CharField(null=True, blank=True, max_length=255)
    aerodrome_status = models.CharField(null=True, blank=True, max_length=255)
    aircraft_access_ind = models.CharField(null=True, blank=True, max_length=255)
    data_source = models.CharField(null=True, blank=True, max_length=255)
    data_source_year = models.CharField(null=True, blank=True, max_length=255)

    class Meta:
        ordering = ("id", )

最后,我有序列化器来转换数据:get.py:(序列化器)

class OpportunityGetSerializer(serializers.ModelSerializer):
    nearest_airport = OpportunityAirportSerializer(required=False)
    
    class Meta:
        model = Opportunity
        fields = (
            "id",
            "opportunity_name",
            "nearest_airport",
        )

distance.py (串行化程序)

class OpportunityAirportSerializer(serializers.ModelSerializer):
    class Meta:
        model = AirportDistance
        fields = ('airport_id', 'airport_distance','airport_name')

上面创建了两个查询而不是一个:

SELECT opportunity.id,
       opportunity.opportunity_name,
       opportunity.nearest_airport,
       airportdistance.id,
       airportdistance.airport_id,
       airportdistance.airport_distance
  FROM opportunity
  LEFT OUTER JOIN airportdistance
    ON (opportunity.nearest_airport = airportdistance.id)
 WHERE opportunity.deleted = false
 ORDER BY opportunity.id ASC

SELECT location.name
  FROM airport
 INNER JOIN location
    ON (airport.location_ptr_id = location.id)
 WHERE airport.location_ptr_id = 1

AirportDistance模型连接到Airport模型,Airport模型又连接到Location模型。在AirportDistance中,我包含了一个混合属性,用于从Airport中检索来自Location模型的名称。我不确定这里的混合属性是否会影响select_related
可以只获取以下查询并混合两个查询:

SELECT opportunity.id,
       opportunity.opportunity_name,
       opportunity.nearest_airport,
       airportdistance.id,
       airportdistance.airport_id,
       airportdistance.airport_distance,
       location."name" 
      FROM opportunity
      LEFT OUTER JOIN airportdistance
        ON (opportunity.nearest_airport = airportdistance.id)
      INNER join airport 
        ON (airport.location_ptr_id = airportdistance.airport_id)
      INNER join location
        ON (location.id = airport.location_ptr_id)
     WHERE opportunity.deleted = false
     ORDER BY opportunity.id ASC
nzkunb0c

nzkunb0c1#

您需要执行select_related('nearest_airport__airport_id')而不是select_related('nearest_airport')
因为AirportDistance在解析airport_name时访问airport_id.name

相关问题