【问题标题】:Django rest framework: exclude results when nested serializer is emptyDjango rest框架:嵌套序列化程序为空时排除结果
【发布时间】:2021-10-19 18:25:35
【问题描述】:

我有一个可以工作的嵌套序列化程序,但我想排除嵌套序列化程序为空的实例。我在嵌套序列化程序上使用的过滤有效,但目前此代码返回所有站点,其中大多数在应用过滤器时具有空的 site_observations 数组。我只想返回包含 site_observations 的站点。我已经为 site_observations 尝试了 SerializerMethodField 但有同样的问题。使用 DRF 3.12

相关模型是站点,以及对站点有 FK 的观察,related field=site_observations

序列化器.py

class FilteredObsListSerializer(serializers.ListSerializer):
    def to_representation(self, data):
        projName = self.context["projName"]
    # this is my filter which works
        data = filter_site_observations(data, self.context["request"],
                                        projName)
        return super(FilteredObsListSerializer, self).to_representation(data)


class ObsFilterSerializer(serializers.ModelSerializer):
    class Meta:
        list_serializer_class = FilteredObsListSerializer
        model = Observation
        fields = "__all__"

class SiteSerializer(GeoFeatureModelSerializer):
    site_observations = ObsFilterSerializer(many=True)

    class Meta:
        model = Site
        geo_field = "geometry"
        fields = ("id", "name", "geometry", "site_observations")


views.py

class SiteList(generics.ListAPIView):
    queryset = Site.objects.all().order_by("pk")
    serializer_class = SiteSerializer
    
    # this is for filtering Observations on segment of an url:
    def get_serializer_context(self):
        context = super(SiteList, self).get_serializer_context()
        context.update({"projName": self.kwargs["name"]}) 
        return context

如何排除 site_observations 为空列表的站点?谢谢。

【问题讨论】:

    标签: python django django-rest-framework django-queryset django-serializer


    【解决方案1】:

    一种方法是告诉您的视图仅适用于满足某些条件的某些对象:

    class SiteList(generics.ListAPIView):
        queryset = Site.objects.filter(
            site_observations__isnull=False,
        ).distinct().order_by('pk')
    

    这将告诉SiteList 仅适用于存在site_observation 关系的Site 对象。您需要在这里调用distinct,如this 所述。

    【讨论】:

    • 感谢您的建议——但是无论site_observations__isnull 是真还是假,或者是否进行了distinct() 调用,这都不会返回任何结果,一个空列表。
    • 糟糕,将此代码添加到错误的位置。现在,它返回所有站点,其中许多站点的 site_observations 为空列表:class SiteList(generics.ListAPIView): serializer_class = SiteSerializer queryset = Site.objects.filter( site_observations__isnull=False, ).distinct().order_by('pk')
    • 尝试独立运行此查询。我怀疑你在 filter_site_observations 中有一些东西会修改结果
    • 同时尝试注释掉filter_site_observations ,看看结果。如果它仍然不起作用,您可以使用您拥有的所有相关更新代码来更新您的问题吗?
    【解决方案2】:

    感谢您的建议,这导致了答案。没有在序列化程序中运行 filter_site_observations 有效。我重新设计了过滤器以在视图中运行并得到我需要的结果。 (我在使用 SerializerMethodField 之前尝试过,但无法正确过滤它;嵌套序列化器似乎是更好的方法。)感谢您的建议!这是过滤器:

    def filter_site_observations(queryset, request, projName):
        '''
        filters a collection on project, observer status
        '''
        if request.user.is_authenticated:
            authprojects = [
                item.project.name
                for item in ObserverStatus.objects.filter(observer=request.user.id)
            ]
            if projName in authprojects:
                return queryset.filter(site_observations__project__name=projName)
            else:
                return queryset.filter(
                    site_observations__project__name=projName).filter(
                        site_observations__private=False)
        else:
            return queryset.filter(
                site_observations__project__name=projName).filter(
                    site_observations__private=False)
    

    和views.py:

    class SiteList(generics.ListAPIView):
        serializer_class = SiteSerializer
    
        def get_serializer_class(self, *args, **kwargs):
            if self.request.method in ("POST", "PUT", "PATCH"):
                return SitePostSerializer
            return self.serializer_class
    
        def get_queryset(self):
            projName = self.kwargs["name"]
            queryset = Site.objects.all().order_by('pk')
            queryset = filter_site_observations(queryset, self.request, projName)
            queryset = queryset.filter(
                site_observations__isnull=False, ).distinct()
            queryset = self.get_serializer_class().setup_eager_loading(queryset)
            return queryset
    

    8 月 28 日更新 实际上,为了获得我需要的过滤器,我必须在both Observation 序列化程序和 SiteList views.py 中运行几乎相同的过滤器。无论我对子数据使用 SerializerMethodField 还是简单的嵌套序列化程序,这都是正确的。否则,我会得到:1) 所有站点,包括没有任何观察的站点,或 2) 具有一些非私有观察但也显示所有私有观察的站点。

    filters.py

    from users.models import ObserverStatus
    
    
    def filter_site_observations(queryset, request, projName):
        '''
        filters a collection on project, observer status; used in views.py.
        Both of these filters seem to be required to get proper filtering.
        '''
        queryset = queryset.filter(site_observations__project__name=projName)
    
        if request.user.is_authenticated:
            authprojects = [
                item.project.name
                for item in ObserverStatus.objects.filter(observer=request.user.id)
            ]
            if projName in authprojects:
                return queryset
            else:
                return queryset.filter(site_observations__private=False)
        else:
            return queryset.filter(site_observations__private=False)
    
    
    def filter_observations(queryset, request, projName):
        '''
        filters observations in ObsSerializer on observer status
        '''
        if request.user.is_authenticated:
            authprojects = [
                item.project.name
                for item in ObserverStatus.objects.filter(observer=request.user.id)
            ]
            if projName in authprojects:
                return queryset
            else:
                return queryset.filter(private=False)
        else:
            return queryset.filter(private=False)
    

    所以我过滤了两次,不知道为什么会这样。

    【讨论】:

      猜你喜欢
      • 2021-06-23
      • 2019-12-23
      • 2016-05-14
      • 1970-01-01
      • 2018-12-13
      • 2015-02-17
      • 2020-07-07
      • 1970-01-01
      相关资源
      最近更新 更多