V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mseasons
V2EX  ›  Django

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

  •  
  •   mseasons · 2018-12-03 08:35:08 +08:00 · 3371 次点击
    这是一个创建于 2180 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在些项目的时候遇到一个有关嵌套关系的 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 (逻辑删除),然后之后做逻辑删除的二级类型项的一级类型外键值都等于这个行,我倾向于这个……但是感觉很蠢。

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

    9 条回复    2018-12-03 19:04:42 +08:00
    jimmyye
        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
    Outliver0
        2
    Outliver0  
       2018-12-03 09:12:53 +08:00
    在二级类型中过滤掉,你每次查询都要过滤掉逻辑删除的部分
    mseasons
        3
    mseasons  
    OP
       2018-12-03 09:14:29 +08:00
    @Outliver0 我知道…… 我的目标就是这个,但是不知道怎么去找到一个最好的方案。
    matrix1010
        4
    matrix1010  
       2018-12-03 09:25:28 +08:00 via Android
    接着用 SerializerMethodField,把 serializer 放里面。或者直接把 model 的 default manager 改了
    mseasons
        5
    mseasons  
    OP
       2018-12-03 09:32:55 +08:00
    @matrix1010 这个方法我也想过,可是如果存在外键很多的话,比如一级类型包含二级类型,其他的表有商品包含规格,等等,代码会很丑吗……
    matrix1010
        6
    matrix1010  
       2018-12-03 10:19:41 +08:00
    @mseasons 那就改 default manager 试试,这样改一个地方就行
    WilliamYang
        7
    WilliamYang  
       2018-12-03 11:03:12 +08:00
    matrix1010
        8
    matrix1010  
       2018-12-03 12:37:44 +08:00
    我刚才又看了看,related manager 不太容易 override,最简单的方法是给 model 加个 property,然后 serializer 的 source 写这个 property。这个在 model 里加比较好,因为 model 里有了其他地方都可以用
    mseasons
        9
    mseasons  
    OP
       2018-12-03 19:04:42 +08:00
    @matrix1010 SerializerMethodField 会导致多余查询很多次吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3257 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 11:49 · PVG 19:49 · LAX 03:49 · JFK 06:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.