你好! 非常感谢这个图书馆! 用我当前的 API 测试它真是太高兴了!
我有两个模型,一个School
和一个SchoolCourse
。 SchoolCourse
与School
$ 具有反向多对一关系。
我希望能够根据 $#$ SchoolCourse
$#$ 的name
过滤School
对象
此外,作为一个延伸目标,我希望最终也能够按SchoolLesson
过滤。
class SchoolModel(Model):
name = CharField(max_length=24, unique=True)
REQUIRED_FIELDS = ["name"]
class Meta:
ordering = ("id",)
def get_courses(self):
school_courses = SchoolCourseModel.objects.filter(school=self)
return school_courses
class SchoolCourseModel(Model):
description = CharField(default="", max_length=200)
name = CharField(max_length=50)
school = ForeignKey(SchoolModel,
related_name="school_course",
on_delete=CASCADE)
REQUIRED_FIELDS = ["school", "name"]
class Meta:
ordering = ("id",)
unique_together = ("school", "name",)
def get_lessons(self):
school_lessons = SchoolLessonModel.objects.filter(course=self)
return school_lessons
哪个 - 如果你在调试视图中使用这些模型,你会看到这个
all_school_models[50].school_course
(Pdb++) <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x10a8177d0>
all_school_models[50].school_course.all()
(Pdb++) <QuerySet [<SchoolCourseModel: SchoolCourseModel object (151)>, <SchoolCourseModel: SchoolCourseModel object (152)>, <SchoolCourseModel: SchoolCourseModel object (153)>]>
all_school_models[50].school_course.all()[0]
(Pdb++) <SchoolCourseModel: SchoolCourseModel object (151)>
all_school_models[50].school_course.all()[0].name
(Pdb++) 'Nihongo Course One'
我制作的过滤器看起来相当简单。
class SchoolFilter(FilterSet):
school_name = CharFilter(field_name="name",
lookup_expr="icontains")
# ---
course_name = CharFilter(field_name="school_course__name",
lookup_expr="icontains")
course_description = CharFilter(field_name="school_course__description",
lookup_expr="icontains")
class Meta:
model = SchoolModel
fields = [
"school_name",
# ---
"course_name",
"course_description"
]
但是,这不起作用。 如果我提出这个要求:
{{API_URL}}/api/v1/schools/?course_name=Nihongo
我把这个作为回应
{
"schools": []
}
我在这里做错了什么?
我是否误解了 django-filters? 我是否误解了如何连接数据模型?
任何指导表示赞赏!
嗨@loganknecht。 作为健全性检查,您能否验证您的 URL 是否正确? 在您的示例 URL 中,查询字符串以/
而不是?
开头。
啊@rpkilby - 抱歉,这是我从Postman
复制和粘贴的疏忽。 该网址实际上是{{API_URL}}/api/v1/schools/?offset=49&course_name=Nihongo
但我删除了offset
以减少混乱并成功地做相反的事情😂
你的例子没有对我提出任何明显的问题。 我最好的猜测是 API 视图存在一些问题。 您是否已将DjangoFilterBackend
添加到您的设置/视图的filter_backends
中? 你有没有设置filterset_class = SchoolFilter
(注意这曾经是filter_class
)?
嘿@rpkilby
这是我的查看代码
class SchoolViewSet(ViewSet):
http_method_names = ["get", "post"]
def list(self, request):
all_school_models = SchoolModel.objects.all()
filtered_school_models = SchoolFilter(request.GET, queryset=all_school_models)
# import pdb
# pdb.set_trace()
paginator = HeaderLinkPagination()
current_page_results = paginator.paginate_queryset(filtered_school_models.qs,
request)
all_schools_serializer = SchoolSerializer(current_page_results,
many=True)
response_data = {
"schools": all_schools_serializer.data
}
response_to_return = paginator.get_paginated_response(response_data)
return response_to_return
pdb.set_trace()
是我发布上述审讯的地方。
我没有设置DjangoFilterBackend
,因为我认为这是一个全局配置,我只在一个端点上测试它。
此外,出于同样的原因,我也没有为班级设置这个。
重要的是要知道我可以在SchoolModel
的名称上使用此过滤器,但是当我过滤反向外键school_course
时,它不起作用。
Gotcha - 所以你直接在视图中创建过滤器集。 在这种情况下,是的,您不需要设置过滤器后端/过滤器集类。
您可以检查数据是否正确,是否有任何错误,或者 SQL 查询的格式是否正确。 尝试:
filtered_school_models = SchoolFilter(request.GET, queryset=all_school_models)
print(filtered_school_models.data)
print(filtered_school_models.errors)
print(filtered_school_models.qs)
print(str(filtered_school_models.qs.query))
@rpkilby这是我看到的
<QueryDict: {'offset': ['49'], 'course_name': ['Nihongo']}>
<QuerySet [<SchoolModel: SchoolModel object (51)>]>
SELECT "piano_gym_api_schoolmodel"."id", "piano_gym_api_schoolmodel"."name", "piano_gym_api_schoolmodel"."school_board_id" FROM "piano_gym_api_schoolmodel" INNER JOIN "piano_gym_api_schoolcoursemodel" ON ("piano_gym_api_schoolmodel"."id" = "piano_gym_api_schoolcoursemodel"."school_id") WHERE UPPER("piano_gym_api_schoolcoursemodel"."name"::text) LIKE UPPER(%Nihongo%) ORDER BY "piano_gym_api_schoolmodel"."id" ASC
@rpkilby这看起来可能是我的分页器实现的问题,看起来像这样
class HeaderLinkPagination(LimitOffsetPagination):
default_limit = settings.DEFAULT_LIMIT
max_limit = settings.DEFAULT_MAX_LIMIT
min_limit = settings.DEFAULT_MIN_LIMIT
min_offset = settings.DEFAULT_MIN_OFFSET
max_offset = settings.DEFAULT_MAX_OFFSET
def get_paginated_response(self, data):
next_url = self.get_next_link()
previous_url = self.get_previous_link()
links = []
header_data = (
(previous_url, "prev"),
(next_url, "next"),
)
for url, label in header_data:
if url is not None:
links.append("<{}>; rel=\"{}\"".format(url, label))
headers = {"Link": ", ".join(links)} if links else {}
return Response(data, headers=headers)
def paginate_queryset(self, queryset, request, view=None):
limit = request.query_params.get("limit")
offset = request.query_params.get("offset")
if limit is None:
limit = settings.DEFAULT_LIMIT
if offset is None:
offset = settings.DEFAULT_OFFSET
limit = int(limit)
if limit > self.max_limit:
error_message = ("Limit should be less than or equal to {0}"
).format(self.max_limit)
errors = {"limit": [error_message]}
raise ValidationError(errors)
elif limit < self.min_limit:
error_message = ("Limit should be greater than or equal to {0}"
).format(self.min_limit)
errors = {"limit": [error_message]}
raise ValidationError(errors)
offset = int(offset)
if offset > self.max_offset:
error_message = ("Offset should be less than or equal to {0}"
).format(self.max_offset)
errors = {"offset": [error_message]}
raise ValidationError(errors)
elif offset < self.min_offset:
error_message = ("Offset should be greater than or equal to {0}"
).format(self.min_offset)
errors = {"offset": [error_message]}
raise ValidationError(errors)
import pdb
pdb.set_trace()
return super(self.__class__, self).paginate_queryset(queryset, request, view)
如果您看到解决方案,请告诉我。 当我试图摆脱这一点时,请继续关注。
我的猜测是这与给定的偏移量有关。 过滤后的查询集中只有 1 个对象,但请求告诉分页器跳过前 49 个项目。 如果你要检查
print(filtered_school_models[49:])
我假设你会得到<QuerySet []>
。
关闭,因为看起来这是一个分页问题。
嘿@rpkilby
我只想说非常感谢你通过这个来告诉我。 这甚至不是django-filter
问题。 我只是一个丁格斯。 你对我避而远之,非常感谢。
您太棒了,再次感谢您提供这个了不起的图书馆!
不用担心。 乐于帮助!
最有用的评论
我的猜测是这与给定的偏移量有关。 过滤后的查询集中只有 1 个对象,但请求告诉分页器跳过前 49 个项目。 如果你要检查
我假设你会得到
<QuerySet []>
。关闭,因为看起来这是一个分页问题。