Django(DRF)-根据子属性在递归字段中过滤父项

时间:2019-05-27 20:14:21

标签: django recursion django-rest-framework

我有一个递归模型。

class Organization(models.Model):
    business_name = models.CharField(max_length=100, unique=True)

    # recursive relationship
    organization = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='organizations')

我有另一个模型是该递归模型的子代,它可以在树中的任何点都是子代。

class Store(models.Model):
    registration_no = models.CharField(max_length=8, default=increment_registration_no, unique=True)
    organization = models.OneToOneField(Organization, on_delete=models.PROTECT, related_name='store', null=True)

在此应用程序的UI中,商店的列表在具有上面的组织头的递归表中列出。我们有一个专门为此列表设计的序列化器。当用户查看此列表时,他们可以按OrganizationStore属性进行过滤。

class StoreSerializer(serializers.ModelSerializer):
    registration_no = serializers.CharField(read_only=True)

    class Meta:
        model = Store
        fields = ('id', 'registration_no')

class StoreFilterSerializer(serializers.ModelSerializer):
    registration_no = serializers.CharField(read_only=True)

    def to_representation(self, value):
        # Turn single object into a query so that we can use django filters
        queryset = Store.objects.filter(pk=value.id)
        registration_no = self.context['request'].query_params.get('registration_no', None)

        if registration_no is not None:
            queryset = queryset.filter(registration_no__icontains=registration_no)

        if queryset:
            # Represent object with serializer defined above
            return StoreSerializer(queryset[0]).data
        else:
            return {}

    class Meta:
        model = Store


class OrganizationsSerializer(serializers.ModelSerializer):
    store = StoreFilterSerializer(read_only=True)
    organizations = RecursiveField(many=True)

    class Meta:
        model = Organization
        fields = ('id', 'business_name', 'organization', 'organizations', 'store')

正如您在上面看到的,如果我们传入registration_no,则可以将商店过滤掉。但是,假设用户输入的字符串与单个商店不匹配。这样一来,商店将不会退货,但是会退还许多机构。在UI中,由于没有商店行,导致表为空,但由于未过滤组织,因此分页菜单具有每个页面。

所以问题是,在应用商店过滤器(registration_no)之后,如何过滤组织是否在递归树下的某个地方有商店?

1 个答案:

答案 0 :(得分:0)

我最终使用的解决方案是过滤所需的商店并获取组织,而不是根据商店属性过滤组织。

过滤商店
各种方法

获取所有商店的父母

all_orgs = []
for store in store_queryset:
  all_orgs.push(store.get_all_parents())

获取所有组织 queryset = Organizations.objects.filter(organization__in = all_orgs) 然后返回组织