Halo!
Sangat menyenangkan menggunakan perpustakaan ini! Saya sangat senang dengan semua kemudahan yang ditawarkannya!
Terima kasih untuk itu!
Tujuan saya saat ini adalah saya ingin memiliki titik akhir yang mendukung kemampuan pencarian pada parameter model, dan juga pemesanan.
Saya memiliki model School
yang memiliki bidang terhitung yang disebut learner_enrolled_count
Respons JSON terlihat seperti ini:
{
"schools": [
{
"id": 6,
"name": "Piano Gym Six",
"courses": [
// ...
],
"learner_enrolled_count": 0
},
{
"id": 7,
"name": "Piano Gym Seven",
"courses": [
// ...
],
"learner_enrolled_count": 5
}
]
}
learner_enrolled_count
adalah bidang terhitung.
Saya telah membaca dokumentasi di sini:
https://django-filter.readthedocs.io/en/stable/ref/filters.html?highlight=order#orderingfilter
dan di sini:
https://django-filter.readthedocs.io/en/stable/ref/filters.html?highlight=order#adding -custom-filter-choices
Jadi berdasarkan itu saya menulis set filter ini di sini:
# ------------------------------------------------------------------------------
# Python Standard Libraries
# ------------------------------------------------------------------------------
# N/A
# ------------------------------------------------------------------------------
# Third-party Libraries
# ------------------------------------------------------------------------------
from django_filters import CharFilter
from django_filters import OrderingFilter
from django_filters.rest_framework import FilterSet
# ------------------------------------------------------------------------------
# Custom Libraries
# ------------------------------------------------------------------------------
from piano_gym_api.versions.v1.models.school_model import SchoolModel
# See:
# https://django-filter.readthedocs.io/en/stable/ref/filters.html#adding-custom-filter-choices
class SchoolOrderingFilter(OrderingFilter):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.extra["choices"] += [
("learner_enrolled_count", "Learner Enrolled Count"),
("-learner_enrolled_count", "Learner Enrolled Count (descending)"),
]
def filter(self, query_set, values):
if(values is None):
return super().filter(query_set, values)
for value in values:
if value in ['learner_enrolled_count', '-learner_enrolled_count']:
return query_set.order_by(value)
return super().filter(query_set, values)
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")
# ---
lesson_name = CharFilter(field_name="school_lesson__name",
lookup_expr="icontains")
lesson_description = CharFilter(field_name="school_lesson__description",
lookup_expr="icontains")
# ---
flash_card_set_name = CharFilter(field_name="school_lesson__flash_card_set__name",
lookup_expr="icontains")
flash_card_set_description = CharFilter(field_name="school_lesson__flash_card_set__description",
lookup_expr="icontains")
# ---
headmaster_username = CharFilter(field_name="school_board__school_board_headmaster__learner__user__username",
lookup_expr="icontains")
board_member_username = CharFilter(field_name="school_board__school_board_member__learner__user__username",
lookup_expr="icontains")
# See:
# https://django-filter.readthedocs.io/en/stable/ref/filters.html#orderingfilter
o = SchoolOrderingFilter(
# tuple-mapping retains order
fields=(
("learner_enrolled_count", "learner_enrolled_count"),
),
# labels do not need to retain order
field_labels={
"learner_enrolled_count": "Total learners enrolled in school",
}
)
class Meta:
model = SchoolModel
fields = [
"school_name",
# ---
"course_name",
"course_description",
# ---
"lesson_name",
"lesson_description",
# ---
"headmaster_username",
"board_member_username"
]
Masalah ini tampaknya tidak memesan sama sekali! Saya tidak tahu mengapa. Ini sangat aneh.
Jika saya memasukkan jejak debug ke dalam metode filter
dari SchoolOrderingFilter
Saya melihat bahwa values
adalah None
. Saya tidak yakin apa yang seharusnya.
Permintaan yang saya buat terlihat seperti ini
{{API_URL}}/api/v1/schools/?offset=5&limit=3&ordering=learner_enrolled_count
Dan tampilan yang menerima permintaan ini terlihat seperti ini:
class SchoolViewSet(ViewSet):
# ...
def list(self, request):
all_school_models = SchoolModel.objects.getBrowseSchoolsData()
school_filter = SchoolFilter(request.GET, queryset=all_school_models)
paginator = HeaderLinkPagination()
current_page_results = paginator.paginate_queryset(school_filter.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
Saya pikir itu benar-benar tidak jelas bagi saya dalam dokumentasi tentang cara menggunakan fitur pemfilteran DAN cara menggunakan pengurutan bidang terhitung.
Apa yang saya lakukan salah? Apakah saya salah memahami fungsi ini? Saya merasa seperti saya melakukan langkah-langkah yang benar untuk ini, tetapi sepertinya tidak bisa membuat fungsi ordering
dari perpustakaan ini berfungsi!
Sekali lagi, terima kasih untuk semuanya!
Hai @loganknecht. Saya harus mengatakan, terima kasih atas laporan masalah yang luar biasa. Ini dimulai dengan baik, dan menjadi lebih baik. Hanya begitu jelas. Jadi terima kasih.
Pertama: sepertinya Anda mendefinisikan SchoolOrderingFilter
dengan nama bidang o
:
o = SchoolOrderingFilter(...)
Jadi ketika Anda mengatakan:
Permintaan yang saya buat terlihat seperti ini
{{API_URL}}/api/v1/schools/?offset=5&limit=3&ordering=learner_enrolled_count
Saya mengharapkan parameter string kueri menjadi o
juga. Apakah ini berfungsi: {{API_URL}}/api/v1/schools/?offset=5&limit=3&o=learner_enrolled_count
?
Kemudian (sedikit yang saya tidak yakin dalam laporan Anda) Anda mengatakan itu _bidang yang dihitung_ -- apa sebenarnya yang Anda maksud? yaitu apakah itu bidang yang muncul pada model, atau apakah itu properti Python?
Cara bertanya lain (bagian dari) yaitu apakah order_by()
pada queryset berfungsi dengan bidang ini? yaitu apakah ini bekerja:
SchoolModel.objects.filter(...).order_by(learner_enrolled_count)
@carltongibson Itu cukup menarik! Saya tidak berharap o
menjadi parameter ordering
ditentukan! Saya tidak mengerti itu dari dokumentasi 😂
o
Yang menarik adalah jika saya menggunakan kueri
{{API_URL}}/api/v1/schools/?offset=5&limit=3&o=learner_enrolled_count
Saya mendapatkan hasil ini:
{
"schools": [
{
"id": 6,
"name": "Piano Gym Six",
"courses": [
# ...
],
"learner_enrolled_count": 0
},
{
"id": 8,
"name": "Piano Gym Eight",
"courses": [
# ...
],
"learner_enrolled_count": 0
},
{
"id": 9,
"name": "Piano Gym Nine",
"courses": [
# ...
],
"learner_enrolled_count": 0
}
]
}
Yang menarik dari ini, sekarang sekolah yang ingin saya urutkan paling atas tidak ada di hasil pencarian ini. Yang berarti bahwa ini mungkin dipesan tetapi pagination masih mengimbangi hasilnya. Namun ketika saya menggunakan learner_enrolled_count
itu di tempat terakhir.
{{API_URL}}/api/v1/schools/?limit=3&o=learner_enrolled_count
Jadi saya menggunakan mengujinya menggunakan -learner_enrolled_count
(menghapus offset dan mengurutkan dengan turun)
{{API_URL}}/api/v1/schools/?limit=3&o=-learner_enrolled_count
dan mendapat tanggapan ini
{
"schools": [
{
"id": 7,
"name": "Piano Gym Seven",
"courses": [
# ...
],
"learner_enrolled_count": 1
},
{
"id": 1,
"name": "Piano Gym",
"courses": [
# ...
],
"learner_enrolled_count": 0
},
{
"id": 2,
"name": "Piano Gym Two",
"courses": [
# ...
],
"learner_enrolled_count": 0
}
]
}
Sepertinya itu berhasil!
learner_enrolled_count
tidak ada pada model itu sendiri. Saya menggunakan anotasi untuk menghitung ini dan memasukkannya ke dalam hasil.
Dengan risiko menyelami model data terlalu banyak, titik akhir ini dimaksudkan sebagai titik masuk tunggal untuk memfilter dan memesan kueri untuk daftar sekolah.
Saya harus mengoptimalkan titik akhir ini menggunakan pengambilan model seperti ini:
class SchoolModelManager(Manager):
def getBrowseSchoolsData(self, *args, **kwargs):
"""Return all Schools that contain lessons with flash card sets.
Does not exclude empty sets, just requires that the school has something
to enroll in
"""
# WARNING: This MUST be imported here otherwise the compilation fails
# because of circular dependencies
from piano_gym_api.versions.v1.models.flash_card_model import FlashCardModel
# from piano_gym_api.versions.v1.models.flash_card_model import PlaySheetMusicFlashCardModel
# from piano_gym_api.versions.v1.models.flash_card_model import TrueOrFalseFlashCardModel
# from piano_gym_api.versions.v1.models.flash_card_set_model import FlashCardSetModel
from piano_gym_api.versions.v1.models.sheet_music_model import SheetMusicModel
# import pdb
# pdb.set_trace()
# --------------------
sheet_music_query_set = (SheetMusicModel.objects.all()
.select_related("school"))
play_sheet_music_flash_card_sheet_music_prefetch = Prefetch("playsheetmusicflashcardmodel__sheet_music",
sheet_music_query_set)
# --------------------
flash_card_query_set = (FlashCardModel.objects.all()
.select_related("flash_card_set",
"playsheetmusicflashcardmodel",
"school",
"trueorfalseflashcardmodel")
.prefetch_related(play_sheet_music_flash_card_sheet_music_prefetch))
flash_card_prefetch = Prefetch("flash_card_set__flash_card", flash_card_query_set)
# --------------------
school_lesson_query_set = (SchoolLessonModel.objects.all()
.select_related("course",
"flash_card_set",
"school")
.prefetch_related(flash_card_prefetch))
school_lesson_prefetch = Prefetch("school_lesson", school_lesson_query_set)
# --------------------
school_course_query_set = (SchoolCourseModel.objects.all()
.select_related("school")
.prefetch_related(school_lesson_prefetch))
school_course_prefetch = Prefetch("school_course", school_course_query_set)
# --------------------
query_set_to_return = (SchoolModel.objects.filter(school_lesson__flash_card_set__isnull=False)
.distinct()
# .annotate(learner_enrolled_count=Count("learner_enrolled_school", distinct=True))
.annotate(learner_enrolled_count=Case(
When(learner_enrolled_school__learner_enrolled_course__learner_enrolled_lesson__is_enrolled=True,
then=1),
default=0,
output_field=IntegerField())
).prefetch_related(school_course_prefetch))
return query_set_to_return
The calculated field
bit adalah di query_set_to_return
variabel. Apa yang dilakukannya adalah mengambil count
dari total pelajar yang terdaftar dan annotates
ke bidang learner_enrolled_count
. Saya tidak tahu apakah ini cara yang benar untuk mencapai ini, tetapi tampaknya berhasil 😂
Satu saran yang akan saya buat adalah mengklarifikasi dalam dokumentasi, baik menggunakan contoh url aktual untuk permintaan atau teks sederhana dan menjelaskan bahwa o
dalam contoh adalah apa yang diekspos sebagai parameter untuk pemesanan.
Tampaknya berfungsi dengan benar sekarang setelah Anda mengklarifikasi parameter o
adalah apa yang ditugaskan oleh filter pemesanan!
Jika querysets
saya sediakan untuk filter
sudah memiliki bidang beranotasi di dalamnya - tampaknya, dari pengujian saya, saya tidak berkewajiban membuat OrderingFilter
kustom saya sendiri
Jadi karena itu saya pikir saya bisa menggunakan OrderingFilter
saja!
Tolong koreksi saya jika saya salah!
Saya percaya itu memecahkan kebingungan saya! Terima kasih!
Hai @loganknecht. Super, sepertinya Anda berhasil. 💃
Jika Anda menggunakan anotasi maka Anda harus dapat memfilter dan memesannya dengan kelas standar ya.
Saya akan membuat tweak ke dokumen.
Terima kasih atas masukan Anda.
@carltongibson dan semua orang, terima kasih untuk perpustakaan yang luar biasa!
Komentar yang paling membantu
Hai @loganknecht. Saya harus mengatakan, terima kasih atas laporan masalah yang luar biasa. Ini dimulai dengan baik, dan menjadi lebih baik. Hanya begitu jelas. Jadi terima kasih.
Pertama: sepertinya Anda mendefinisikan
SchoolOrderingFilter
dengan nama bidango
:Jadi ketika Anda mengatakan:
Saya mengharapkan parameter string kueri menjadi
o
juga. Apakah ini berfungsi:{{API_URL}}/api/v1/schools/?offset=5&limit=3&o=learner_enrolled_count
?Kemudian (sedikit yang saya tidak yakin dalam laporan Anda) Anda mengatakan itu _bidang yang dihitung_ -- apa sebenarnya yang Anda maksud? yaitu apakah itu bidang yang muncul pada model, atau apakah itu properti Python?
Cara bertanya lain (bagian dari) yaitu apakah
order_by()
pada queryset berfungsi dengan bidang ini? yaitu apakah ini bekerja: