Halo! Terima kasih banyak untuk perpustakaan ini! Sangat menyenangkan untuk mengujinya dengan API saya saat ini!
Saya memiliki dua model, School
dan SchoolCourse
. SchoolCourse
memiliki hubungan terbalik banyak ke satu ke School
.
Saya ingin dapat memfilter objek School
berdasarkan name
dari SchoolCourse
Selain itu, sebagai tujuan tambahan, saya juga ingin dapat memfilter menurut SchoolLesson
pada akhirnya.
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
Yang mana - jika Anda bermain dengan model ini dalam tampilan debug, Anda akan melihat ini
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'
Filter yang saya buat tampaknya cukup mudah.
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"
]
Namun ini tidak berhasil. Jika saya membuat permintaan ini:
{{API_URL}}/api/v1/schools/?course_name=Nihongo
Saya mendapatkan ini kembali sebagai tanggapan
{
"schools": []
}
Apa yang saya lakukan salah di sini?
Apakah saya salah mengartikan Django-filters? Apakah saya salah mengartikan cara menghubungkan model data?
Setiap bimbingan dihargai!
Hai @loganknecht. Sama seperti pemeriksaan kewarasan, dapatkah Anda memverifikasi bahwa URL Anda benar? Di URL contoh Anda, string kueri dimulai dengan /
alih-alih ?
.
Ah @rpkilby - maaf, ini adalah kesalahan saya dari menyalin dan menempel dari Postman
. Urlnya sebenarnya {{API_URL}}/api/v1/schools/?offset=49&course_name=Nihongo
tapi saya menghapus offset
agar tidak terlalu membingungkan dan berhasil melakukan yang sebaliknya 😂
Contoh Anda tidak menimbulkan masalah yang jelas bagi saya. Tebakan terbaik saya adalah ada beberapa masalah dengan tampilan API. Sudahkah Anda menambahkan DjangoFilterBackend
ke pengaturan/tampilan Anda filter_backends
? Dan apakah Anda sudah menetapkan filterset_class = SchoolFilter
(perhatikan bahwa ini dulu filter_class
)?
Hai @rpkilby
Ini kode tampilan yang saya miliki
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()
adalah tempat saya memposting interogasi di atas.
Saya tidak menetapkan DjangoFilterBackend
karena saya berasumsi bahwa itu adalah konfigurasi global dan saya hanya menguji ini pada satu titik akhir.
Selain itu, saya juga tidak mengatur ini untuk kelas karena alasan yang sama.
Penting untuk diketahui bahwa SAYA BISA menggunakan filter ini atas nama SchoolModel
tetapi ketika saya memfilter pada kunci asing terbalik school_course
itu tidak berfungsi.
Gotcha - jadi Anda membuat filterset dalam tampilan secara langsung. Dalam hal ini, ya, Anda tidak perlu mengatur kelas backend/filterset filter.
Anda mungkin memeriksa untuk melihat apakah data terlihat benar, jika ada kesalahan, atau jika kueri SQL dibuat dengan benar. Mencoba:
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 Inilah yang saya lihat
<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 Ini sepertinya ada masalah dengan implementasi paginator saya yang terlihat seperti ini
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)
Jika Anda melihat solusi, beri tahu saya. Tetap disini sementara saya mencoba untuk menghilangkan ini.
Dugaan saya adalah ini terkait dengan offset yang diberikan. Hanya ada 1 objek dalam kumpulan kueri yang difilter, tetapi permintaan tersebut memberi tahu paginator untuk melewati 49 item pertama. Jika Anda ingin memeriksa
print(filtered_school_models[49:])
Saya berasumsi Anda akan mendapatkan <QuerySet []>
.
Penutupan, karena sepertinya ini adalah masalah pagination.
Hai @rpkilby
Saya hanya ingin mengucapkan terima kasih banyak untuk berbicara saya melalui ini. Ini bahkan bukan masalah django-filter
. Aku hanya menjadi dingus. Anda karet merunduk saya sangat dihargai.
Anda luar biasa, dan sekali lagi, terima kasih untuk perpustakaan yang luar biasa ini!
Jangan khawatir. Saya senang bisa membantu!
Komentar yang paling membantu
Dugaan saya adalah ini terkait dengan offset yang diberikan. Hanya ada 1 objek dalam kumpulan kueri yang difilter, tetapi permintaan tersebut memberi tahu paginator untuk melewati 49 item pertama. Jika Anda ingin memeriksa
Saya berasumsi Anda akan mendapatkan
<QuerySet []>
.Penutupan, karena sepertinya ini adalah masalah pagination.