Django model属性基于ManyToManyField时如何限制#查询

2024-04-26 01:10:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用Django Rest框架为现有(遗留)SQL数据库构建一个readapi。问题是这样会产生太多的查询。你知道吗

我想选择一个Widget及其(大约40个)相关的小部件,包括每个相关小部件的widget_technology。小部件的技术取决于某个标记的存在与否(我知道这是次优的数据库设计,但它是遗留的……)。问题是这会导致40多个查询(每个相关小部件一个)。你知道吗

有什么办法解决吗?你知道吗

我一直在看代码中DRF部分的prefetch_related('widget_tags'),但这似乎没有帮助。你知道吗

这是主表:

class Widgets(models.Model):
    widget_id = models.AutoField(primary_key=True)
    widget_slug = models.CharField(unique=True, max_length=70)
    widget_name = models.CharField(max_length=70)
    widget_tags = models.ManyToManyField('Tags', through='IsTag')
    related_widgets = models.ManyToManyField('Widgets', through='Similar', related_name='similar')

    @property
    def widget_technology(self):
        if self.widget_tags.filter(tag_slug='tech_1').exists():
            return 'TECH_1'
        elif self.widget_tags.filter(tag_slug='tech_2').exists():
            return 'TECH_2'

    class Meta:
        managed = False
        db_table = 'widgets'

为完整起见,以下是其他表格:

class Similar(models.Model):
    first_widget = models.ForeignKey(
        Widgets, models.DO_NOTHING, primary_key=True, related_name='similar_first_widget'
    )
    second_widget = models.ForeignKey(
        Widgets, models.DO_NOTHING, related_name='similar_second_widget'
    )
    score = models.IntegerField()

    class Meta:
        managed = False
        db_table = 'similar'
        unique_together = (('first_widget', 'second_widget'),)

class IsTag(models.Model):
    is_tag_widget = models.ForeignKey(Widgets, models.DO_NOTHING, primary_key=True)
    is_tag_tag = models.ForeignKey('Tags', models.DO_NOTHING)

    class Meta:
        managed = False
        db_table = 'is_tag'
        unique_together = (('is_tag_widget', 'is_tag_tag'),)


class Tags(models.Model):
    tag_id = models.AutoField(primary_key=True)
    tag_slug = models.CharField(max_length=100)

    class Meta:
        managed = False
        db_table = 'tags'

编辑:添加视图

class WidgetDetail(APIView):
    def get_object(self, slug):
        try:
            return Widgets.objects.get(widget_slug=slug)
            # tried this but didn't solve the issue:
            # return Widgets.objects.prefetch_related('related_widgets', 'related_widgets__widget_tags').get(widget_slug=slug)
    except Widgets.DoesNotExist:
        raise Http404

    def get(self, request, slug, format=None):
        widget = self.get_object(slug)
        serializer = FullWidgetSerializer(widget)
        return Response(serializer.data)

以及序列化程序:

class FullWidgetSerializer(serializers.ModelSerializer):
    # special cases
    widget_tags = SimpleTagSerializer(many=True, read_only=True)
    related_widgets = SimpleWidgetSerializer(many=True, read_only=True)

    class Meta:
        model = Widgets     
        fields = (
            'widget_slug', 'related_widgets', 'widget_tags', 'widget_technology')

class SimpleWidgetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Widgets     
        fields = ('widget_slug', 'widget_technology')

Tags: selftruegetreturnismodelstagtags

热门问题