有关 drf 中一些关于嵌套关系的问题想请教

2018-12-03 08:35:08 +08:00
 mseasons

在些项目的时候遇到一个有关嵌套关系的 bug,想了一段时间,想到几种解决方案,但是不知道什么样子是最优的,来问问前辈们……

问题描述:我用 drf 写的后端接口,在写序列化类的时候,遇到了嵌套关系的问题,比如我现在有一个一级类型一个二级类型,一级类型包含二级类型,在二级类型表中有一个一级类型的外键,删除操作用逻辑删除,将删除的那一行的 status 字段设置值为 1。

这样单独请求哪个接口的时候都不会出问题。代码如下:

class ProductPrimaryTypeViewSet(BaseViewSet):
    queryset = ProductPrimaryType.objects.filter(status=0)
    serializer_class = ProductPrimaryTypeSerializer


class ProductSecondaryTypeViewSet(BaseViewSet):
    queryset = ProductSecondaryType.objects.filter(status=0)
    serializer_class = ProductSecondaryTypeSerializer

但是嵌套的时候就会出问题,我在一级类型的序列化类中添加了二级类型的嵌套,代码如下:

class ProductSecondaryTypeSerializer(serializers.ModelSerializer):
    product_primary_type_name = serializers.SerializerMethodField()

    def get_product_primary_type_name(self, obj):
        return obj.product_primary_type.name

    class Meta:
        model = ProductSecondaryType
        fields = ('id', 'name', 'product_primary_type_id', 'product_primary_type_name')


class ProductPrimaryTypeSerializer(serializers.ModelSerializer):
    product_secondary_types = ProductSecondaryTypeSerializer(many=True, source='productsecondarytype_set')

    class Meta:
        model = ProductPrimaryType
        fields = ('id', 'name', 'product_secondary_types')

这个时候直接访问二级类型的接口是可以直接过滤掉已经逻辑删除的行的,但是访问一级类型的接口的时候还是会显示已经删除的行,想问一下,怎么做筛选呢?

我想了一些方法,但是不知道怎么做才是最优的,因为未来需求可能变,乱写可能改代码的时候很痛苦。所以来请教一下。

方法 1 :重写二级类型序列化类的 to_representation 方法,在返回的时候如果 status=1 则直接返回 None,然后在一级类型序列化类的 to_representation 方法中过滤掉所有的 None。

方法 2:创建一个没用的一级类型数据,然后让这个数据的 status=1 (逻辑删除),然后之后做逻辑删除的二级类型项的一级类型外键值都等于这个行,我倾向于这个……但是感觉很蠢。

希望有前辈能帮我解答疑惑。

3397 次点击
所在节点    Django
9 条回复
jimmyye
2018-12-03 09:10:32 +08:00
“但是访问一级类型的接口的时候还是会显示已经删除的行”,说的是会显示已删除的二级类型吧?过滤应该在 queryset 中进行,可以在 prefetch 的时候用`Prefetch`过滤掉。
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.Prefetch
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.prefetch_related
Outliver0
2018-12-03 09:12:53 +08:00
在二级类型中过滤掉,你每次查询都要过滤掉逻辑删除的部分
mseasons
2018-12-03 09:14:29 +08:00
@Outliver0 我知道…… 我的目标就是这个,但是不知道怎么去找到一个最好的方案。
matrix1010
2018-12-03 09:25:28 +08:00
接着用 SerializerMethodField,把 serializer 放里面。或者直接把 model 的 default manager 改了
mseasons
2018-12-03 09:32:55 +08:00
@matrix1010 这个方法我也想过,可是如果存在外键很多的话,比如一级类型包含二级类型,其他的表有商品包含规格,等等,代码会很丑吗……
matrix1010
2018-12-03 10:19:41 +08:00
@mseasons 那就改 default manager 试试,这样改一个地方就行
WilliamYang
2018-12-03 11:03:12 +08:00
matrix1010
2018-12-03 12:37:44 +08:00
我刚才又看了看,related manager 不太容易 override,最简单的方法是给 model 加个 property,然后 serializer 的 source 写这个 property。这个在 model 里加比较好,因为 model 里有了其他地方都可以用
mseasons
2018-12-03 19:04:42 +08:00
@matrix1010 SerializerMethodField 会导致多余查询很多次吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/513675

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX