Django REST框架预取不适用于具有多个指向同一目标的外键的模型

tvmytwxo  于 2023-06-25  发布在  Go
关注(0)|答案(1)|浏览(67)

我正在编写一个端点来从Django REST框架中的“Term”模型中获取数据,我试图通过预取数据来减少查询。具体来说,有一个模型“TermRelation”,它保存了我想从中预取数据的各个术语之间的向量关系得分。简化后的模型如下所示:

models.py

class Term(models.Model):
    term = models.CharField(max_length=255, verbose_name=_('Term'), null=True, db_index=True)

class TermRelation(models.Model):
    src_term = models.ForeignKey(Term, on_delete=models.CASCADE, verbose_name=_('Source term'),
                                    related_name='src_term_relation')
    trg_term = models.ForeignKey(Term, on_delete=models.CASCADE, verbose_name=_('Target term'),
                                    related_name='trg_term_relation')
    vector_sim = models.FloatField(blank=True, null=True, default=0.0, verbose_name=_('Vector similarity'), help_text=_('Cosine vector similarity.'))

下面是简化的视图:

views.py

class TermsList(generics.ListCreateAPIView):
    def get_queryset(self):
        queryset = Term.objects.prefetch_related(
            'src_term_relation',
            'trg_term_relation',
            'note_set',
            'usage_set'
        ).all()
        return queryset

还有其他与术语相关的模型,例如“Note”和“Usage”,预取正在工作,只有对于关系,它仍然进行一系列查询。我已经包含了Django SQL debug结果的屏幕截图,或者更确切地说,前面的几行,因为这将持续一段时间,使用相同的查询。你可以看到Django确实运行了预取操作,但仍然会进行相同的查询,就好像它没有发生一样。
我做错了什么?这是否与“TermRelation”有两个指向同一模型的ForeignKey字段或REST框架不知道如何解析相关名称有关?

编辑:

我想我找到了一些东西,问题似乎在别处。在序列化器中,有一个方法字段用于计算关系的数量:

class TermSerializer(serializers.ModelSerializer):
    relations_count = serializers.SerializerMethodField()

    def get_relations_count(self, obj):
        rels = TermRelation.objects.filter(Q(src_term=obj) | Q(trg_term=obj))
        return len(rels)

    class Meta:
        model = Term
        fields = '__all__'

我假设它对序列化器返回的每个术语的所有TermRelations运行一个查询,忽略预取的数据。有没有更好的办法?

mgdq6dx1

mgdq6dx11#

试试这个,也许它会解决额外的查询问题

class TermSerializer(serializers.ModelSerializer):
    relations_count = serializers.SerializerMethodField()

    def get_relations_count(self, obj):
        return obj.src_term_relation.count() + obj.trg_term_relation.count()

相关问题