misalkan kita memiliki model dalam django yang didefinisikan sebagai berikut:
class Literal:
name = models.CharField(...)
...
Bidang nama tidak unik, sehingga dapat memiliki nilai duplikat. Saya perlu menyelesaikan tugas berikut: Pilih semua baris dari model yang memiliki setidaknya satu nilai duplikat dari name
bidang tersebut.
Saya tahu cara melakukannya menggunakan SQL biasa (mungkin bukan solusi terbaik):
select * from literal where name IN (
select name from literal group by name having count((name)) > 1
);
Jadi, apakah mungkin untuk memilih ini menggunakan django ORM? Atau solusi SQL yang lebih baik?
sql
django
django-orm
memaksa
sumber
sumber
Literal.objects.values('name').annotate(name_count=Count('name')).filter(name_count__gt=1)
?Cannot resolve keyword 'id_count' into field
values_list('name', flat=True)
Count
penjelasan untuk disimpan sebagai, defaultnya adalah[field]__count
. Bagaimanapun, sintaks garis bawah ganda itu juga bagaimana Django menafsirkan anda ingin melakukan penggabungan. Jadi, pada dasarnya ketika Anda mencoba memfilter itu, Django mengira Anda sedang mencoba melakukan penggabungancount
yang jelas-jelas tidak ada. Cara mengatasinya adalah menentukan nama untuk hasil anotasi Anda, yaituannotate(mycount=Count('id'))
dan kemudian memfilternyamycount
.values('name')
setelah panggilan Anda untuk membuat anotasi, Anda dapat menghapus pemahaman daftar dan mengatakanLiteral.objects.filter(name__in=dupes)
yang akan memungkinkan semua ini dijalankan dalam satu kueri.Ini ditolak sebagai edit. Jadi inilah jawaban yang lebih baik
Ini akan mengembalikan a
ValuesQuerySet
dengan semua nama duplikat. Namun, Anda kemudian dapat menggunakan ini untuk membuat regulerQuerySet
dengan memasukkannya kembali ke kueri lain. Django ORM cukup pintar untuk menggabungkan ini menjadi satu kueri:Panggilan ekstra ke
.values('name')
setelah panggilan anotasi terlihat sedikit aneh. Tanpa ini, subkueri gagal. Nilai ekstra menipu ORM agar hanya memilih kolom nama untuk subkueri.sumber
.order_by()
untuk?GROUP BY
klausa SQL , dan itu merusak banyak hal. Mengetahui hal itu saat bermain dengan Subquery (di mana Anda melakukan pengelompokan yang sangat mirip melalui.values()
)coba gunakan agregasi
sumber
Jika Anda menggunakan PostgreSQL, Anda dapat melakukan sesuatu seperti ini:
Ini menghasilkan kueri SQL yang agak sederhana ini:
sumber
Jika Anda ingin menghasilkan daftar nama saja tetapi bukan objek, Anda bisa menggunakan kueri berikut ini
sumber