【问题标题】:Filter nested query if no results in Django如果在 Django 中没有结果,则过滤嵌套查询
【发布时间】:2019-12-02 20:32:28
【问题描述】:

当我使用这个查询时,我有三个基本的嵌套序列化器当前正在返回一个嵌套数据结构(如下所示):

queryset = Regulation.objects.all() 
serializer_class = RegulationSerializer(queryset, many=True)

我的models.py如下:

class Regulation(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.TextField(null=False)
    documents = models.ManyToManyField(Document, related_name='regulation_documents', through="DocumentRegulation")
    portal = models.BooleanField(default=False)

class RegulationVersion(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    regulation = models.ForeignKey(Regulation, related_name='versions', blank=False, null=False, on_delete=models.DO_NOTHING)
    name = models.CharField(max_length=20, null=False)

class Iteration(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    version = models.ForeignKey(RegulationVersion, related_name='iterations', blank=False, on_delete=models.DO_NOTHING)
    organization = models.ForeignKey(Organization, blank=False, null=False, on_delete=models.DO_NOTHING)
    name = models.CharField(max_length=60, blank=False, null=False)
    date_created = models.DateTimeField(_('created at'), auto_now_add=True)
    created_by_user = models.ForeignKey(User, blank=False, null=False, on_delete=models.DO_NOTHING)

    class Meta:
        unique_together= ('name', 'organization', 'version')

serializers.py 结构如下:

class FilteredIterationSerializer(serializers.ListSerializer):
    def to_representation(self, data):
        organization_id = self.context.get('organization_id')
        data = data.filter(organization=organization_id)
        return super(FilteredIterationSerializer, self).to_representation(data)python

class IterationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Iteration
        list_serializer_class = FilteredIterationSerializer
        fields = ('id', 'organization', 'version', 'name', 'date_created', 'created_by_user')

class VersionSerializer(serializers.ModelSerializer):
    iterations = IterationSerializer(many=True, read_only=True)
    class Meta:
        model = RegulationVersion
        fields = ('name', 'iterations')

class RegulationSerializer(serializers.ModelSerializer):
    versions = VersionSerializer(many=True, read_only=True)
    class Meta:
        model = Regulation
        fields = ('name', 'versions')
        depth = 2

序列化输出:

[{ name: "2019-final"
  versions: {
       0: { name: "2019-01",
            iterations: (25) [{…}, {…}, {…}]
          }
       1: { name: "2019-02",
            iterations: []
          }
 }
{ name: "2020-final"
  versions: {
       0: { name: "2020-01",
            iterations: []
          }
       1: { name: "2020-02",
            iterations: []
          }
 }]

我如何排除没有任何iterations的所有versions,以及排除没有任何@的regulations 987654328@或嵌套iterations

使用上面的序列化输出,我不想返回name"2020-final" 的对象,因为它的versions 都没有iterations。我也不想返回name"2019-02"version 对象,因为它没有迭代。所需的输出如下所示:

[{ name: "2019-final"
  versions: {
       0: { name: "2019-01",
            iterations: (25) [{…}, {…}, {…}]
          }
 }]

【问题讨论】:

  • 您能否为所有涉及的模型添加您的models.py 代码?
  • 请同时包含FilteredIterationSerializer 的代码,以及您可能使用的任何django-filters 代码。
  • 非常感谢您清理问题...我从未见过格式如此精美的问题。我有时会犹豫放太多代码,不想让别人不知所措。

标签: django django-models django-rest-framework django-views


【解决方案1】:

背景:

只要任何嵌套的序列化程序传递了many=True 参数,DRF 就会在后台创建一个列表序列化程序实例(检查BaseSerializer.__new__BaseSerializer.many_init 方法),并将原始序列化程序保持为child 的类属性列表序列化程序。然后每当需要序列化时(当您访问serializer.data 时),像往常一样,调用列表序列化程序的to_representation,然后列表序列化程序依次调用child 序列化程序的to_representation 并返回一个列表作为输出。

默认的列表序列化器是serializers.ListSerializer,它可以通过序列化器Meta类选项list_serializer_class来改变。

因此,如果我们需要更改表示,我们需要创建列表序列化程序类并覆盖to_representation 以返回修改后的响应。


首先,让我们处理VersionSerializer 以仅显示具有相关迭代的版本:

class VersionListSerializer(serializers.ListSerializer):

    def to_representation(self, data):
        versions = data.all() if isinstance(data, models.Manager) else data 
        return [
            self.child.to_representation(version)
            for version in versions
            if version.iterations.exists()
        ]

class VersionSerializer(serializers.ModelSerializer): 
  iterations = IterationSerializer(many=True, read_only=True)

  class Meta:
      model = RegulationVersion
      list_serializer_class = VersionListSerializer
      fields = ('name', 'iterations')

RegulationSerializer 的类似逻辑,仅显示有相关版本的法规:

class RegulationListSerializer(serializers.ListSerializer):

    def to_representation(self, data):
        regulations = data.all() if isinstance(data, models.Manager) else data 
        return [
            self.child.to_representation(regulation)
            for regulation in regulations
            if regulation.versions.exists()
        ]

class RegulationSerializer(serializers.ModelSerializer):
    versions = VersionSerializer(many=True, read_only=True)

    class Meta:
        model = Regulation
        list_serializer_class = RegulationListSerializer
        fields = ('name', 'versions')

【讨论】:

  • 非常感谢,这太棒了。在没有迭代并且版本被删除的情况下,它仍然返回规则,但我相信这是因为在 VersionListSerializer 之前评估了RegulationListSerializer。如果实际上没有法规版本,则可以按预期工作。就我而言,这实际上没问题,因为我可以只计算列出的版本数,如果为零,则将其从数组中删除。这比递归地计算版本和迭代,然后在必要时删除规则要简单得多。谢谢!
  • @ambe5960 对法规的过滤应该可以工作。将serializer_class 更改为RegulationSerializer,然后查看。您是否还更改了视图集的 list 方法中有关序列化程序的任何内容?
猜你喜欢
  • 1970-01-01
  • 2017-02-08
  • 2021-11-10
  • 2021-02-06
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多