Djagno:在单个数据库查询中通过ManyToMany“通过”模型获取对象

时间:2018-10-02 15:24:11

标签: python django

给出以下模型:

class Places(models.Model):
    #...

class Tour(models.Model):
    places = ManyToManyField(A, through='TourPlaces')

class TourPlaces(models.Model):
    tour = ForeignKey(Tour, on_delete=models.CASCADE)
    place = ForeignKey(Place, on_delete=models.CASCADE)
    #...

如何构建查询集,以便可以在SQL端获取Places所属的Tours,而又不必反复访问数据库?伪示例:

for place in Places.objects.(some kind of annotation maybe?):
    print(place.tours[0])

代替

for place in Places.objects.all():
    print(TourPlaces.objects.get(place=place).tour[0])

上下文:使用上面在SerializerMethodField中的代码,我的REST Framework ModelSerializer for Places太慢了。

2 个答案:

答案 0 :(得分:0)

class Places(models.Model):
    first_field = models.CharField(max_length=50)
    second_field = models.CharField(max_length=50)

class Tour(models.Model):
    places = ManyToManyField(A, through='TourPlaces')

class TourPlaces(models.Model):
    tour = ForeignKey(Tour, on_delete=models.CASCADE)
    place = ForeignKey(Place, on_delete=models.CASCADE)

然后:

TourPlaces.objects.filter(place__first_field = 'some')

答案 1 :(得分:0)

我通过使用带有反向集的prefetch_related解决了这个问题并提高了性能:

for place in Places.objects.prefetch_related('tour_set').all():
    print(str(place.tour_set.first()))

请参见https://docs.djangoproject.com/en/2.1/ref/models/querysets/#prefetch-related

我的REST视图集和模型序列化器现在看起来像这样:

class PlaceViewSet(viewsets.ModelViewSet):
    parser_classes = (JSONParser,)
    serializer_class = PlaceSerializer
    queryset = Place.objects.prefetch_related('tour_set')

class PlaceSerializer(serializers.ModelSerializer):
    tour = serializers.SerializerMethodField('_tour')

    def _tour(self, obj):
        try:
            return str(obj.tour_set.first())
        except:
            return ""

    class Meta:
        model = Place
        fields = (
            '...',
            'tour',
        )