Saya mencoba membangun pencarian untuk situs Django yang saya bangun, dan dalam pencarian itu, saya mencari dalam 3 model yang berbeda. Dan untuk mendapatkan pagination pada daftar hasil pencarian, saya ingin menggunakan tampilan object_list generik untuk menampilkan hasilnya. Tetapi untuk melakukan itu, saya harus menggabungkan 3 querysets menjadi satu.
Bagaimana saya bisa melakukan itu? Saya sudah mencoba ini:
result_list = []
page_list = Page.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term))
article_list = Article.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
post_list = Post.objects.filter(
Q(title__icontains=cleaned_search_term) |
Q(body__icontains=cleaned_search_term) |
Q(tags__icontains=cleaned_search_term))
for x in page_list:
result_list.append(x)
for x in article_list:
result_list.append(x)
for x in post_list:
result_list.append(x)
return object_list(
request,
queryset=result_list,
template_object_name='result',
paginate_by=10,
extra_context={
'search_term': search_term},
template_name="search/result_list.html")
Tetapi ini tidak berhasil. Saya mendapatkan kesalahan saat mencoba menggunakan daftar itu dalam tampilan umum. Daftar ini tidak memiliki atribut clone.
Adakah yang tahu bagaimana saya bisa menggabungkan ketiga daftar page_list
,, article_list
dan post_list
?
django
search
django-queryset
django-q
espenhogbakk
sumber
sumber
union
.Jawaban:
Menggabungkan daftar pertanyaan menjadi daftar adalah pendekatan yang paling sederhana. Jika basis data akan dipukul untuk semua queryset (misalnya karena hasilnya perlu disortir), ini tidak akan menambah biaya lebih lanjut.
Menggunakan
itertools.chain
lebih cepat daripada mengulang setiap daftar dan menambahkan elemen satu per satu, karenaitertools
diimplementasikan dalam C. Ini juga mengkonsumsi lebih sedikit memori daripada mengubah setiap queryset ke dalam daftar sebelum digabungkan.Sekarang mungkin untuk mengurutkan daftar yang dihasilkan misalnya berdasarkan tanggal (seperti yang diminta dalam komentar hasen j untuk jawaban lain). The
sorted()
Fungsi nyaman menerima generator dan mengembalikan daftar:Jika Anda menggunakan Python 2.4 atau yang lebih baru, Anda bisa menggunakan
attrgetter
bukan lambda. Saya ingat membaca tentang hal itu menjadi lebih cepat, tetapi saya tidak melihat perbedaan kecepatan yang terlihat untuk satu juta daftar item.sumber
from itertools import groupby
unique_results = [rows.next() for (key, rows) in groupby(result_list, key=lambda obj: obj.id)]
'list' object has no attribute 'complex_filter'
Coba ini:
Ini mempertahankan semua fungsi querysets yang bagus jika Anda mau
order_by
atau serupa.Harap dicatat: ini tidak berfungsi pada querysets dari dua model yang berbeda.
sumber
|
adalah operator serikat pekerja, bukan bitwise ATAU.Terkait, untuk mencampur querysets dari model yang sama, atau untuk bidang serupa dari beberapa model, Dimulai dengan Django 1.11 sebuah
qs.union()
metode juga tersedia:https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet.union
sumber
Anda dapat menggunakan
QuerySetChain
kelas di bawah ini. Saat menggunakannya dengan paginator Django, seharusnya hanya mengenai database denganCOUNT(*)
permintaan untuk semua querysets danSELECT()
queries hanya untuk querysets yang catatannya ditampilkan pada halaman saat ini.Perhatikan bahwa Anda perlu menentukan
template_name=
apakah menggunakanQuerySetChain
dengan tampilan umum, bahkan jika kueri rantai dirantai semua menggunakan model yang sama.Dalam contoh Anda, penggunaannya adalah:
Kemudian gunakan
matches
dengan paginator seperti yang Anda gunakanresult_list
dalam contoh Anda.The
itertools
Modul diperkenalkan dengan Python 2.3, sehingga harus tersedia di semua versi Python Django berjalan pada.sumber
Kelemahan besar dari pendekatan Anda saat ini adalah inefisiensi dengan set hasil pencarian yang besar, karena Anda harus menarik seluruh set hasil dari database setiap kali, meskipun Anda hanya bermaksud menampilkan satu halaman hasil.
Untuk hanya menarik objek yang sebenarnya Anda butuhkan dari database, Anda harus menggunakan pagination pada QuerySet, bukan daftar. Jika Anda melakukan ini, Django sebenarnya mengiris QuerySet sebelum kueri dieksekusi, jadi kueri SQL akan menggunakan OFFSET dan LIMIT untuk hanya mendapatkan catatan yang benar-benar akan Anda tampilkan. Tetapi Anda tidak dapat melakukan ini kecuali jika Anda dapat menjejalkan pencarian Anda ke dalam satu permintaan.
Mengingat ketiga model Anda memiliki bidang judul dan badan, mengapa tidak menggunakan warisan model ? Hanya memiliki ketiga model yang diwarisi dari leluhur yang sama yang memiliki judul dan tubuh, dan melakukan pencarian sebagai permintaan tunggal pada model leluhur.
sumber
Jika Anda ingin mengaitkan banyak kueri, coba ini:
dimana: docs adalah daftar querysets
sumber
Dikutip dari https://groups.google.com/forum/#!topic/django-users/6wUNuJa4jVw . Lihat Alex Gaynor
sumber
Ini dapat dicapai dengan dua cara baik.
Cara pertama untuk melakukan ini
Gunakan operator gabungan untuk queryset
|
untuk mengambil gabungan dua queryset. Jika kedua queryset milik model yang sama / model tunggal daripada itu mungkin untuk menggabungkan queryset dengan menggunakan operator serikat.Sebagai contoh
Cara ke-2 untuk melakukan ini
Salah satu cara lain untuk mencapai operasi gabungan antara dua queryset adalah dengan menggunakan fungsi rantai itertools .
sumber
Persyaratan:
Django==2.0.2
,django-querysetsequence==0.8
Jika Anda ingin menggabungkan
querysets
dan masih keluar denganQuerySet
, Anda mungkin ingin memeriksa django-queryset-sequence .Tapi satu catatan tentang itu. Hanya butuh dua
querysets
karena itu argumen. Tetapi dengan pythonreduce
Anda selalu dapat menerapkannya ke beberapaqueryset
s.Dan itu saja. Di bawah ini adalah situasi yang saya hadapi dan bagaimana saya bekerja
list comprehension
,reduce
dandjango-queryset-sequence
sumber
Book.objects.filter(owner__mentor=mentor)
melakukan hal yang sama? Saya tidak yakin ini kasus penggunaan yang valid. Saya pikirBook
mungkin perlu memiliki beberapaowner
sebelum Anda perlu mulai melakukan hal seperti ini.inilah sebuah ide ... cukup tarik ke bawah satu halaman penuh hasil dari masing-masing dari ketiganya dan kemudian buang 20 yang paling tidak berguna ... ini menghilangkan kueryset besar dan dengan begitu Anda hanya mengorbankan sedikit kinerja alih-alih banyak.
sumber
Ini akan melakukan pekerjaan tanpa menggunakan lib lainnya
sumber
Fungsi rekursif ini menggabungkan array queryset menjadi satu queryset.
sumber