按外键关系中的字段过滤
Filter by fields from foreignKey relationships
我有一堆模型,其中一些是连接的(通过外键关系),我写了一个序列化程序,它允许我打印出我想要的所有连接字段,并省略我所做的不想看。伟大的。现在我还有一个基本过滤器,它使用包含所有外键的模型 (PmP
),但现在我想为字段添加另一个过滤器(字段名称 e
来自 PmPr
模型)来自不同的模型,通过外键连接读入的模型(模型 PmP
中的 li
连接到模型 PmL
包含字段 pro
连接到模型 PmPr
字段 e
所在的位置)。但我不知道该怎么做,据我所知,我无法在 view
(PmPLListView
) 中设置两个 filter_class
es?!而且我不知道如何通过外键关系访问该字段。那么我该怎么做呢?如果我可以通过我现有的过滤器从 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
我有一堆模型,其中一些是连接的(通过外键关系),我写了一个序列化程序,它允许我打印出我想要的所有连接字段,并省略我所做的不想看。伟大的。现在我还有一个基本过滤器,它使用包含所有外键的模型 (PmP
),但现在我想为字段添加另一个过滤器(字段名称 e
来自 PmPr
模型)来自不同的模型,通过外键连接读入的模型(模型 PmP
中的 li
连接到模型 PmL
包含字段 pro
连接到模型 PmPr
字段 e
所在的位置)。但我不知道该怎么做,据我所知,我无法在 view
(PmPLListView
) 中设置两个 filter_class
es?!而且我不知道如何通过外键关系访问该字段。那么我该怎么做呢?如果我可以通过我现有的过滤器从 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