在些项目的时候遇到一个有关嵌套关系的 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 (逻辑删除),然后之后做逻辑删除的二级类型项的一级类型外键值都等于这个行,我倾向于这个……但是感觉很蠢。
希望有前辈能帮我解答疑惑。
1
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 |
2
Outliver0 2018-12-03 09:12:53 +08:00
在二级类型中过滤掉,你每次查询都要过滤掉逻辑删除的部分
|
4
matrix1010 2018-12-03 09:25:28 +08:00 via Android
接着用 SerializerMethodField,把 serializer 放里面。或者直接把 model 的 default manager 改了
|
5
mseasons OP @matrix1010 这个方法我也想过,可是如果存在外键很多的话,比如一级类型包含二级类型,其他的表有商品包含规格,等等,代码会很丑吗……
|
6
matrix1010 2018-12-03 10:19:41 +08:00
@mseasons 那就改 default manager 试试,这样改一个地方就行
|
7
WilliamYang 2018-12-03 11:03:12 +08:00
|
8
matrix1010 2018-12-03 12:37:44 +08:00
我刚才又看了看,related manager 不太容易 override,最简单的方法是给 model 加个 property,然后 serializer 的 source 写这个 property。这个在 model 里加比较好,因为 model 里有了其他地方都可以用
|
9
mseasons OP @matrix1010 SerializerMethodField 会导致多余查询很多次吧
|