Фильтр по полям из отношений foreignKey

У меня есть куча моделей, и некоторые из них связаны (отношениями foreign-key), и я написал сериализатор, который позволяет мне вывести все связанные поля, которые я хочу, и оставить то, что я не хочу видеть. Отлично. Теперь у меня есть базовый фильтр, который использует модель (PmP), содержащую все foreignkey, но теперь я хочу добавить еще один фильтр для поля (имя поля e из PmPr модели) из другой модели, той, которая считывается через соединение с иностранным ключом (li в модели PmP соединяется с моделью PmL, содержащей поле pro, которая соединяется с моделью PmPr, где находится поле e). Но я не знаю, как это сделать, и, насколько я понимаю, я не могу установить два filter_class внутри моего view (PmPLListView)?! И я не знаю, как получить доступ к полю через отношение foreignkey. Так как же мне поступить? Если я могу получить доступ к полю e из модели PmPr через мой существующий фильтр - это тоже меня устроит, мне не нужно два класса фильтра (если это вообще возможно). Это была просто моя первая мысль. (btw. извините за странные имена, но, к сожалению, мне не разрешено писать настоящие имена)

вот мои модели (по крайней мере, актуальные):

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 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()

О, я понял! Я могу получить доступ к внешнему отношению с двумя символами подчеркивания. Поэтому я изменил свой класс Filter следующим образом:

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

Вернуться на верх