按外键关系中的字段过滤

Filter by fields from foreignKey relationships

我有一堆模型,其中一些是连接的(通过外键关系),我写了一个序列化程序,它允许我打印出我想要的所有连接字段,并省略我所做的不想看。伟大的。现在我还有一个基本过滤器,它使用包含所有外键的模型 (PmP),但现在我想为字段添加另一个过滤器(字段名称 e 来自 PmPr模型)来自不同的模型,通过外键连接读入的模型(模型 PmP 中的 li 连接到模型 PmL 包含字段 pro 连接到模型 PmPr 字段 e 所在的位置)。但我不知道该怎么做,据我所知,我无法在 view (PmPLListView) 中设置两个 filter_classes?!而且我不知道如何通过外键关系访问该字段。那么我该怎么做呢?如果我可以通过我现有的过滤器从 PmPr 模型访问 e 字段——那对我来说也很好,我不需要两个过滤器 classes(如果可能的话)。这只是我的第一个想法。 (顺便说一句,很抱歉奇怪的名字,但不幸的是我不允许写真名)

这些是我的模型(至少是相关模型):

class PmP(models.Model):
    created_at = models.DateTimeField()
    pr = models.DecimalField(max_digits=6, decimal_places=2)
    li = models.ForeignKey(PmL, models.DO_NOTHING)
    se = models.ForeignKey('PmSe', models.DO_NOTHING)

    class Meta:
        managed = False
        db_table = 'pm_p'



class PmL(models.Model):
    u = models.TextField()
    pro = models.ForeignKey('PmPr', models.DO_NOTHING)
    sh = models.ForeignKey('PmS', models.DO_NOTHING)
    active = models.IntegerField()

    class Meta:
        managed = False
        db_table = 'pm_l'



class PmSe(models.Model):
    name = models.TextField()
    s_i_id = models.TextField(blank=True, null=True)
    sh = models.ForeignKey('PmS',
                             models.DO_NOTHING,
                             blank=True,
                             null=True)

    class Meta:
        managed = False
        db_table = 'pm_se'


class PmPr(models.Model):
    name = models.TextField()
    e = models.CharField(max_length=13)
    created_at = models.DateTimeField()
    cus = models.ForeignKey(PmC, models.DO_NOTHING)
    u_v_p = models.DecimalField(max_digits=10,
                              decimal_places=2,
                              blank=True,
                              null=True)
    cf = models.IntegerField(blank=True, null=True)
    s_k_u = models.IntegerField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'pm_pr'

这是我的序列化器的样子:

class PmPLSerializer(serializers.ModelSerializer):
    # id = serializers.SerializerMethodField('get_l_id')
    u = serializers.SerializerMethodField('get_l_u')
    sh = serializers.SerializerMethodField('get_sh_name')
    name = serializers.SerializerMethodField('get_pro_name')
    e = serializers.SerializerMethodField('get_pro_e')
    u_v_p = serializers.SerializerMethodField('get_pro_u_v_p')
    s_k_u = serializers.SerializerMethodField('get_pro_s_k_u')
    se = serializers.SerializerMethodField('get_se_name')
    pr = serializers.SerializerMethodField('get_pr')
    created_at = serializers.SerializerMethodField('get_created_at')

    class Meta:
        model = PmP
        # fields = '__all__'
        fields = ('u', 'sh', 'name', 'e', 's_k_u', 'u_v_p', 'pr',
                  'created_at', 'se')
        depth = 2

    def get_l_id(self, obj):
        return obj.li.id

    def get_l_u(self, obj):
        return obj.li.u

    def get_sh_name(self, obj):
        return obj.li.sh.name

    def get_pro_name(self, obj):
        return obj.li.pro.name

    def get_pro_e(self, obj):
        return obj.li.pro.e

    def get_pro_u_v_p(self, obj):
        return obj.li.pro.u_v_p

    def get_pro_s_k_u(self, obj):
        return obj.li.pro.s_k_u

    def get_se_name(self, obj):
        return obj.se.name

    def get_pr(self, obj):
        return obj.pr

    def get_created_at(self, obj):
        return obj.created_at

这是我的过滤器 class:

class PmPFilter(rfilters.FilterSet):
    class Meta:
        model = PmP
        fields = [
            "created_at",
            "pr",
        ]

    for field in ["pr"]:
        exec(f'min_{field} = rfilters.NumberFilter(field, lookup_expr="gte")')
        exec(f'max_{field} = rfilters.NumberFilter(field, lookup_expr="lte")')


    # filter by date as "is_less_than_or_equal_to"
    written_to = rfilters.CharFilter(method="created_at_to", label="created_at to")

    # filter by date as "is_greater_than_or_equal_to"
    written_from = rfilters.CharFilter(method="created_at_from", label="created_at from")

    # filter by exact date
    written = rfilters.CharFilter(method="created_at_exact", label="created_at exact")

    def created_at_exact(self, queryset, name, value):
        year, month, day, hour, minute, second = self.parse_date(value)
        cdate = datetime(year, month, day, hour, minute, second)
        return queryset.filter(created_at=cdate)

    def created_at_to(self, queryset, name, value):
        year, month, day, hour, minute, second = self.parse_date(value)
        cdate = datetime(year, month, day, hour, minute, second)
        return queryset.filter(created_at__lte=cdate)

    def created_at_from(self, queryset, name, value):
        year, month, day, hour, minute, second = self.parse_date(value)
        cdate = datetime(year, month, day, hour, minute, second)
        return queryset.filter(created_at__gte=cdate)

    def parse_date(self, value):
        return (
            parser.parse(value).year,
            parser.parse(value).month,
            parser.parse(value).day,
            parser.parse(value).hour,
            parser.parse(value).minute,
            parser.parse(value).second,
        )

最后,这是我的观点:

class PmPLListView(generics.ListAPIView):
    queryset = PmP.objects.all()
    serializer_class = PmPLSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
    ordering_fields = ["created_at", "pr"]
    filter_class = PmPFilter
    fields = ("created_at", "pr")
    filter_fields = fields
    search_fields = fields

    def get_queryset(self):
        """
        This view should return a list of all data
        """
        return PmP.objects.filter()

哦,我明白了!我可以通过两个下划线访问外部关系。所以我将过滤器 class 修改为:

class PmPFilter(rfilters.FilterSet):
    class Meta:
        model = PmPrice
        fields = [
            "created_at",
            "pr",
            "li__pro__e",
        ]
 ...

在我的 PmPLListView 视图中,我还添加了双下划线来访问该字段:

class PmPLListView(generics.ListAPIView):
    queryset = PmP.objects.all()
    serializer_class = PmPLSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
    ordering_fields = ["created_at", "pr"]
    filter_class = PmPFilter
    fields = ("created_at", "pr", "li__pro__e")
    filter_fields = fields
    search_fields = fields

现在我可以按字段过滤 e