Python 如何在Django DRF中过滤嵌套序列化程序的字段
我有两个模型,分别是“学校”和“学生”。我为学校创建了每个序列化程序和嵌套序列化程序,并将学生序列化程序作为嵌套字段 在这里,我想使用“django filters”对序列化程序的字段应用过滤器,它几乎可以工作,但是……问题是,当我过滤嵌套字段,即“学生字段”时,它不会显示所需的结果。 我的模型是:Python 如何在Django DRF中过滤嵌套序列化程序的字段,python,django,django-rest-framework,Python,Django,Django Rest Framework,我有两个模型,分别是“学校”和“学生”。我为学校创建了每个序列化程序和嵌套序列化程序,并将学生序列化程序作为嵌套字段 在这里,我想使用“django filters”对序列化程序的字段应用过滤器,它几乎可以工作,但是……问题是,当我过滤嵌套字段,即“学生字段”时,它不会显示所需的结果。 我的模型是: class School(models.Model): name = models.CharField(max_length=256) principal = models.Char
class School(models.Model):
name = models.CharField(max_length=256)
principal = models.CharField(max_length=256)
location = models.CharField(max_length=256)
is_government = models.BooleanField(default=True)
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=256)
age = models.PositiveIntegerField()
school = models.ForeignKey(School,related_name='students',on_delete = models.CASCADE)
is_adult = models.BooleanField(default=True)
def __str__(self):
return self.name
我的序列化程序是:
class SchoolSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
# Instantiate the superclass normally
super(SchoolSerializer, self).__init__(*args, **kwargs)
allow_students = self.context.get("allow_students",None)
if allow_students:
self.fields['students'] = StudentSerializer(many=True, context=kwargs['context'], fields=['name','age','is_adult'])
class Meta():
model = School
fields = '__all__'
class StudentSerializer(DynamicFieldsModelSerializer):
class Meta():
model = Student
fields = '__all__'
以下是我在视图中使用的过滤器:
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import FilterSet
from django_filters import rest_framework as filters
class SchoolStudentAPIView(generics.ListAPIView, mixins.CreateModelMixin):
queryset = School.objects.all()
serializer_class = SchoolSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('is_government','students__is_adult')
这里的问题是,当我搜索students_uuis_u成人(这是一个嵌套字段)时,它会过滤掉成人学生和非成人学生的列表
有人能补充一些额外的东西或提供另一种解决方案吗?谢谢你解决了这个问题
首先,Django Rest框架没有执行您期望的查询。让我们看看如何检查
调试实际查询的一种方法是向SchoolStudentAPIView类添加自定义列表方法,如下所示:
def listself,请求,*args,**kwargs:
resp=super.listrequest,*args,**kwargs
从django.db导入连接
printconnection.Query或在此处设置断点
返回响应
这个方法只是将所有执行的查询转储到控制台
connection.querys的最后一个元素是我们应该关注的。它将是一个dict,其sql键类似于:
选择'school`.'id`、'school`.'name`、'school`.'location`、'school`.'isu government``
从'school'在'school'上的'school'内部连接'student'。'id`='student`.'school\u id`
其中'student`.'u成人`=1
此查询意味着SchoolSerializer将通过至少有一名成人学生的所有学校
顺便说一下,同一所学校可以出现多次,因为上面的查询为每个成年学生生成一行
最后,SchoolSerializer显示学校中的所有学生,而不考虑任何过滤选项:这就是此行的目的
如果允许学生:
self.fields['students']=studentserializerName=True。。。
建议的解决方案
在序列化程序中找不到简单的解决方案。也许更简单的方法是在SchoolStudentAPIView类中编写一个自定义列表方法
该方法将:
查找查询字符串参数student\u is\u成人:如果有,该方法将在我命名为filtered\u students的queryset中的每个学校上创建一个自定义字段,并使该字段指向正确的student queryset。
将上下文参数传递给SchoolSerializer,告诉它已筛选学生
SchoolSerializer类将以两种不同的方式填充其students字段,具体取决于上下文参数的存在与否。特别是,如果传递的上下文中存在students\u is\u成人密钥,则StudentSerializer字段将具有源kwarg
代码:
类SchoolStudentAPIViewgenerics.ListAPIView,mixin.CreateModelMixin:
...
def listself,请求,*args,**kwargs:
学校=self.get\u queryset
ctx={}
如果request.query参数中的“学生”是“成人”:
按成人过滤=boolrequest.query参数['students\uuu是成人']
ctx={
“学生是成人”:按成人筛选,
“允许学生”:对,
}
对于学校的学生:
s、 过滤的学生=s.students.filteris\u成人=按成人过滤
ser=SchoolSerializerdata=schools,many=True,context=ctx
ser.U有效吗
返回应答器数据
类SchoolSerializerserializers.ModelSerializer:
定义初始自我,*args,**kwargs:
超级学校序列化程序,self.\u初始参数,**kwargs
allow_students=self.context.getallow_students,无
如果允许学生:
如果已筛选学生,则将“源”更改为自定义字段
filter\u active=self.context.getposts\u处于活动状态,无
如果筛选器_未处于活动状态,请执行以下操作:
stud=StudentSerializer
source='filtered_students',many=True,
context=kwargs['context'],
字段=[“姓名”、“年龄”、“是否成年”]
其他:
stud=StudentSerializer
many=True,context=kwargs['context'],
字段=[“姓名”、“年龄”、“是否成年”]
self.fields['student']=stud
谢谢@paolo,但这并没有解决问题,相反,现在它只显示自己的字段,这意味着不显示嵌套字段。列表代码没有设置所需的dict键-我已修复。请再试一次。无论如何,试着调试代码以了解发生了什么。例如,PyCharm有一个很好的内置调试器。