Membuat query¶
Sekali anda telah membuat data models 1 anda, Django otomatis memberikan anda pemisahan API yang membuat anda membuat, mengambil, memperbaharui dan menghapus obyek. Dokumen ini menjelaskan bagaimana menggunakan API ini. mengacu pada data model reference 2 untuk rincian penuh dari beragam pilihan pencarian model.
Sepanjang panduan ini (dan dalam acuan), kami akan mengacu ke model-model berikut, yang meliputi aplikasi Weblog:
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
def __str__(self):
return self.name
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
number_of_comments = models.IntegerField()
number_of_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
Membuat obyek¶
Untuk mewakili data tabel-basisdata dalam obyek Python, Django menggunakan sistem intuitif: Sebuah kelas model mewakili sebuah tabel basisdata, dan sebuah instance dari kelas itu mewakili rekaman tertentu dalam tabel basisdata.
Untuk membuat sebuah obyek, instansiasi itu menggunakan argumen katakunci pada kelas model, kemudian memanggil save()
untuk menyimpan itu ke basisdata.
Menganggap model tinggal di berkas mysite/blog/models.py
, ini adalah sebuah contoh:
>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()
Ini melakukan pernyataan SQL INSERT
dibelakang layar. Django tidak mengenai basisdata sampai anda secara jelas memanggil save()
.
Cara save()
tidak mempunyai nilai kembalian.
Menyimpan perubahan ke obyek¶
Untuk menyimpan perubahan ke sebuah obyek yang sudah ada di basisdata gunakan save()
.
Diberikan instance Blog
b5
yang telah disimpan ke basisdata, contoh ini merubah namanya dan memperbaharui rekamannya dalam basisdata:
>>> b5.name = 'New name'
>>> b5.save()
Ini melakukan pernyataan SQL UPDATE
dibelakang layar. Django tidak mengenai basisdata sampai anda secara jelas memanggil save()
.
Menyimpan bidang ForeignKey
dan ManyToManyField
¶
Updating a ForeignKey
field works exactly the same
way as saving a normal field -- assign an object of the right type to the field
in question. This example updates the blog
attribute of an Entry
instance entry
, assuming appropriate instances of Entry
and Blog
are already saved to the database (so we can retrieve them below):
>>> from blog.models import Blog, Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()
Memperbaharui sebuah ManyToManyField
bekerja sedikit berbeda -- gunakan metode add()
pada bidang untuk menambahkan rekaman ke hubungan. Contoh ini menambahkan instance Author
joe
ke obyek entry
:
>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)
Untuk menambahkan banyak rekaman pada ManyToManyField
dalam sekali pergi, sertakan banyak argumen dalam panggilan pada add()
, seperti ini:
>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)
Django akan mengeluh jika anda mencoba memberikan atau menambahkan sebuah obyek dari jenis salah.
Mengambil obyek¶
Untuk mengambil obyek-obyek dari basisdata anda, bangun sebuah QuerySet
melalui Manager
pada kelas model anda.
Sebuah QuerySet
mewakili sebuah kumpulan dari ibyek-obyek dari basisdata anda. itu dapat memiliki nol, satu atau banyak penyaring. Penyaring mempersempit hasil permintaan berdasarkan pada parameter yang diberikan. Dalam istilah SQL, QuerySet
menyamakan pada pernyataan SELECT
, dan penyaring membatasi klausa seperti WHERE
atau LIMIT
.
Anda mendapatkan QuerySet
dengan menggunakan Manager
model anda. Setiap model mempunyai setidaknya satu Manager
, dan itu memanggil objects
secara awalan. Akses itu langsung melalui kelas model, seperti itu:
>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
...
AttributeError: "Manager isn't accessible via Blog instances."
Catatan
Managers
dapat diakses hanya melalui kelas-kelas model, daripada dari instance model, untuk melaksanakan pemisahan diantara tindakan "tingkat-tabel" dan tindakan "tingkat-rekam".
Manager
adalah sumber utama dari QuerySets
untuk sebuah model. Sebagai contoh, Blog.objects.all()
mengembalikan QuerySet
yang mengandung semua obyek Blog
dalam basisdata.
Mengambil semua obyek¶
Cara termudah untuk mengambil obyek dari sebuah tabel adalah mendapatkan semua dari mereka. Untuk melakukan ini, gunakan metode all()
pada sebuah Manager
:
>>> all_entries = Entry.objects.all()
Metode all()
mengembalikan semua QuerySet
dari semua obyek dalam basisdata.
Mengambil obyek spesifik dengan menyaring¶
QuerySet
dibalikkan oleh all()
menggambarkan semua obyek-obyek dalam tabel basisdata. Biasanya, meskipun, anda akan butuh memilih hanya sub kumpulan dari kumpulan lengkap dari obyek.
Untuk membuat semacam sub kumpulan, anda menyaring QuerySet
awalan, menambahkan kondisi penyaringan. Dua cara paling umum untuk menyaring QuerySet
adalah:
filter(**kwargs)
- Mengembalikan
QuerySet
baru mengandung obyek-obyek yang cocok dari parameter pencarian yang diberikan. exclude(**kwargs)
- Mengembalikan
QuerySet
baru mengandung obyek-obyek yang tidak cocok dari parameter pencarian yang diberikan.
Parameter pencarian (**kwargs
dalam penertian fungsi diatas) harus berupa dalam bentuk digambarkan dalam Field lookups dibawah.
Sebagai contoh, untuk mendapatkan QuerySet
dari masukan blog dari tahun 2006, gunakan filter()
seperti itu:
Entry.objects.filter(pub_date__year=2006)
Dengan kelas pengelola awalan, itu adalah sama seperti:
Entry.objects.all().filter(pub_date__year=2006)
Menambatkan penyaringan¶
Hasil dari pengilangan QuerySet
adalah itu sendiri QuerySet
, jadi itu mungkin menambatkan pengilangan bersama-sama. Sebagai contoh:
>>> Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.date.today()
... ).filter(
... pub_date__gte=datetime.date(2005, 1, 30)
... )
Ini mengambil awal QuerySet
dari semua masukan dalam basisdata, tambah sebuah penyaring, kemudian sebuah pengecualian, kemudian penyaring lain. Hasil akhir adalah sebuah QuerySet
mengandung semua masukan dengan judul yang mulai dengan "What", yang diterbitkan diantara 30 Januari 2005, dan hari saat ini.
Disaring QuerySet
adalah unik¶
Setiap kali anda menyaring sebuah QuerySet
, anda mendapatkan QuerySet
merek-baru yaitu tidak ada cara mengikat ke QuerySet
sebelumnya. Setiap penyaringan membuat QuerySet
terpisah dan berbeda yang dapat disimpan, digunakan dan digunakan kembali.
Contoh:
>>> q1 = Entry.objects.filter(headline__startswith="What")
>>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
>>> q3 = q1.filter(pub_date__gte=datetime.date.today())
Ketiga QuerySets
ini terpisah. Pertama adalah dasar QuerySet
mengandung semua masukan yang mengandung judul dimulai dengan "What". kedua adalah sub kumpulan dari pertama, dengan sebuah tambahan kriteria yang tidak menyertakan rekaman yang pub_date
adalah hari ini atau di masa depan. Ketiga adalah sub kumpulan dari pertama, dengan tambahan kriteria yang hanya memilih rekaman yang pub_date
adalah hari ini atau di masa depan. Awalan QuerySet
(q1
) tidak terpengaruh dengan pengolahan penyaringan.
QuerySet
adalah lazy¶
QuerySets
adalah lazy -- tindakan dari membuat QuerySet
tidak melibatkan aktifitas basisdata apapun. Anda dapat menumpuk penyaring bersama-sama sepanjang hari, dan Django tidak sebenarnya menjalankan permintaan sampai QuerySet
dinilai. Coba lihat contoh ini:
>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains="food")
>>> print(q)
Meskipun ini terlihat mengenai basisdata tiga kali, sebenarnya itu mengenai basisdata hanya sekali, pada baris terakhir (print(q)
). Secara umum, hasil dari QuerySet
tidak diambil dari basisdata sampai anda "meminta" untuk mereka. Ketika anda melakukan, QuerySet
dinilai dengan mengakses basisdata. Untuk rincian lebih pada sebenarnya ketika penilaian mengambil tempat, lihat Ketika QuerySet dinilai.
Mengambil obyek tunggal dengan get()
¶
filter()
akan selalu memberikan anda QuerySet
, bahkan jika hanya obyek tunggal yang cocok permintaan - dalam kasus ini, itu akan berupa QuerySet
mengandung unsur tunggal.
Jika anda mengetahui hanya ada satu obyek yang cocok permintaan anda, anda dapat menggunakan metode meth:~django.db.models.query.QuerySet.get pada sebuah Manager
yang mengembalikan obyek secara langsung:
>>> one_entry = Entry.objects.get(pk=1)
Anda dapat menggunakan pernyataan permintaan apapun dengan get()
, seperti dengan filter()
- kembali, lihat Field lookups dibawah.
Catat bahwa ada perbedaan diantara menggunakan get()
, dan menggunakan filter()
dengan potongan [0]
. Jika tidak ada hasil yang cocok dengan permintaan, get()
akan memunculkan pengecualian DoesNotExist
. Pengecualian ini adalah sebuah atribut dari kelas model yang permintaan sedang dilakukan - jadi dalam kode diatas, jika tidak ada obyek Entry
dengan primary key dari 1, Django akan memunculkan Entry.DoesNotExist
.
Demikain pula, Django akan mengeluh jika lebih dari satu barang cocok permintaan get()
. Dalam kasus ini, itu akan memunculkan MultipleObjectsReturned
, yang kembali adalah sebuah atribut dari kelas model itu sendiri.
Cara QuerySet
lain¶
Kebanyakan waktu anda akan gunakan all()
, get()
, filter()
dan exclude()
ketika anda butuh mencari obyek-obyek dari basisdata. Bagaimanapun, itu jauh dari semua yang ada; lihat QuerySet API Reference untuk daftar lengkap dari semua ragam metode QuerySet
.
Membatasi QuerySet
¶
Gunakan sub kumpulan dari sintaksis memotong-array Python untuk membatasi QuerySet
anda pada nomor tertentu dari hasil. Ini adalah setara daro klausa LIMIT
dan OFFSET
SQL.
Sebagai contoh, ini mengembalikan 5 obyek pertama (LIMIT 5
):
>>> Entry.objects.all()[:5]
Ini mengembalikan enam dari 10 obyek (OFFSET 5 LIMIT 5
):
>>> Entry.objects.all()[5:10]
Pengindeksan negatif (yaitu Entry.objects.all()[-1]
) tidak didukung.
Umumnya, memotong QuerySet
mengembalikan QuerySet
baru -- itu tidak menilai permintaan. Sebuah pengevualian jika anda menggunakan parameter "step" dari sintaksis potongan Python. Sebagai contoh, ini akan sebenarnya menjalankan permintaan untuk menjalankan daftar dari setiap detik obyek dari 10 pertama:
>>> Entry.objects.all()[:10:2]
Penyaring atau pengurut lebih lanjut dari irisan queryset dilarang karena sifat ambigu dari bagaimana itu mungkin bekerja.
To retrieve a single object rather than a list
(e.g. SELECT foo FROM bar LIMIT 1
), use an index instead of a slice. For
example, this returns the first Entry
in the database, after ordering
entries alphabetically by headline:
>>> Entry.objects.order_by('headline')[0]
Ini kurang lebih setara pada:
>>> Entry.objects.order_by('headline')[0:1].get()
Catat, bagaimanapun, yang pertama dari ini akan memunculkan IndexError
selagi kedua akan memunculkan DoesNotExist
jika tidak ada obyek cocok dari kriteria yang diberikan. Lihat get()
untuk rincian lebih.
Bidang pencarian¶
Pencarian bidang adalah bagaimana anda menentukan isi dari sebuah klausa SQL WHERE
. Mereka ditentukan sebagai argumen kata kunci pada QuerySet
metode metode filter()
, exclude()
dan get()
.
Argumen kata kunci pencarian dasar mengambil formulir field__lookuptype=value
. (Itu adalah garis bawah ganda). Sebagai contoh:
>>> Entry.objects.filter(pub_date__lte='2006-01-01')
terjemahan (kurang lebih) ke dalam SQL berikut:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
Bagaimana ini mungkin
Python mempunyai kemampuan untuk menentukan fungsi-fungsi yang menerima argumen nilai-nama beruubah-ubah yang namanya dan nilainya dinilai pada waktu berjalan. Untuk informasi lebih, lihat Keyword Arguments dalam tutorial Python resmi.
Bidang ditentukan dalam pencarian harus berupa nama dari bidang model. meskipun ada satu pengecualian, dalam kasus dari ForeignKey
anda dapat menentukan nama bidang akhiran dengan _id
. Dalam kasus ini, parameter nilai diharapkan mengandung nilai mentah dari foreign primary key model. Sebagai contoh:
>>> Entry.objects.filter(blog_id=4)
Jika anda melewatkan argumen kata kunci tidak sah, fungsi pencarian akan memunculkan TypeError
.
API basisdata mendukung sekitar dua lusin jenis pencarian; acuan lengkap dapat ditemukan dalam field lookup reference 1. Untuk memberikan anda selera dari apa yang tersedia, ini adalah beberapa dari pencarian lebih umum anda mungkin gunakan:
exact
Sebuah pencocokan "tepat". Sebagai contoh:
>>> Entry.objects.get(headline__exact="Cat bites dog")
Akan membangkitkan SQL bersama baris ini:
SELECT ... WHERE headline = 'Cat bites dog';
Jika anda tidak menyediakan jenis pencarian -- yaitu, jika argumen kata kunci anda tidak mengandung garis bawah ganda -- jenis pencarian dianggap
tepat
.Sebagai contoh, dua pernyataan berikut adalah setara:
>>> Blog.objects.get(id__exact=14) # Explicit form >>> Blog.objects.get(id=14) # __exact is implied
Ini adalah untuk kenyamanan, karena pencarian
exact
adalah kasus umum.iexact
Pencocokan kasus-tidak-peka. Jadi, permintaan:
>>> Blog.objects.get(name__iexact="beatles blog")
Akan cocok
Blog
berjudul"Beatles Blog"
,"beatles blog"
, atau bahkan"BeAtlES blOG"
.contains
Percobaan penahanan kasus-peka . Sebagai contoh:
Entry.objects.get(headline__contains='Lennon')
Kurang lebih menterjemahkan ke SQL ini:
SELECT ... WHERE headline LIKE '%Lennon%';
Catat ini akan cocok dengan judul
'Today Lennon honored'
tetapi tidak'today lennon honored'
.Ada juga versi kasus-tidak-peka,
icontains
.startswith
,endswith
- Pencarian mulai-dengan dan berakhir-dengan, masing-masing. Ada juga versi kasus-tidak-peka dipanggil
istartswith
daniendswith
.
Kembali, ini hanya menggores permukaan. Acuan lengkap dapat ditemukan di field lookup reference 1.
Pencarian yang menjangkau hubungan¶
Django offers a powerful and intuitive way to "follow" relationships in
lookups, taking care of the SQL JOIN
s for you automatically, behind the
scenes. To span a relationship, use the field name of related fields
across models, separated by double underscores, until you get to the field you
want.
Contoh ini mengambil semua obyek Entry
dengan Blog
yang name
adalah 'Beatles Blog'
:
>>> Entry.objects.filter(blog__name='Beatles Blog')
Jangkauan ini dapat sedalam anda sukai.
It works backwards, too. To refer to a "reverse" relationship, use the lowercase name of the model.
Contoh ini mengambil semua obyek Blog
yang setidaknya saru Entry
yang headline
mengandung 'Lennon'
:
>>> Blog.objects.filter(entry__headline__contains='Lennon')
Jika anda menyaring terhadap banyak hubungan dan satu dari model mengengah tidak mempunyai nilai yang memenuhi kondisi penyaring, Django akan memperlakukan itu sebagai jika sebuah kosong (semua nilai adalah NULL
), tetapi obyek sah disana. Semua ini berarti bahwa tidak ada kesalahan akan dimunculkan. Sebagi contoh, dalam penyaringan ini:
Blog.objects.filter(entry__authors__name='Lennon')
(jika ada model Author
terkait), jika tidak ada author
terkait dengan sebuah masukan, itu akan diperlakukan seperti jika tidak ada juga name
terlampir, daripada memunculkan kesalahan karena dari author
hilang. Biasanya ini adalah tepatnya apa anda ingin miliki terjadi. Kasus satu-satunya dimana itu mungkin membingungkan adalah jika anda menggunakan isnull
. Jadi:
Blog.objects.filter(entry__authors__name__isnull=True)
akan mengembalikan obyek Blog
yang mempunyai name
kosong pada author
dan juga itu yang mempunyai author
kosong pada entry
. Jika anda tidak ingin obyek terakhir itu, anda dapat menulis:
Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)
Membentangkan hubungan banyak-nilai¶
Ketika anda menyaring sebuah obyek berdasarkan pada sebuah ManyToManyField
atau membalikkan ForeignKey
, ada dua perbedaan urutan dari penyaringan anda mungkin tertarik. Pertimbangkan hubungan Blog
/Entry
(Blog
pada Entry
adalah hubungan one-to-many). Kami mungkin tertarik dalam menemukan blog yang memiliki sebuah masukan yang mempunyai kedua "Lennon" dalam judul dan telah diterbitkan di 2008. Atau kami mungkin ingin menemukan blog yang mempunyai sebuah masukan dengan "Lennon" dalam judul sama halnya sebuah masukan yang telah diterbitkan di 2008. Sejak ada banyak masukan terkait dengan Blog
tunggal, kedua dari permintaan ini adalah memungkinkan dan masuk akal dalam beberapa keadaan
Jenis keadaan sama muncul dengan ManyToManyField
. Sebagai contoh, jika sebuah Entry
mempunyai ManyToManyField
disebut tags
, kami mungkin ingin menemukan masukan terkait ke etiket disebut "music" dan "bands" atau kami mungkin ingin sebuah masukan yang mengandung sebuth etiket dengan nama dari "music" dan status dari "public".
Untuk menangani kedua keadan ini, Django mempunyai cari yang cocok dari mengolah panggilan filter()
. Apapun didalam panggilan filter()
tunggal diberlakukan secara terus menerus untuk menyaring barang-barang mencocokkan semua lingkungan tersebut. Panggilan filter()
berturut-turut lebih lanjut membatasi setelan dari obyek, tetapi untuk hubungan banyak-nlai, mereka berlaku ke obyek apapun terkait pada model utama, tidak perlu obyek-obyek itu yang telah dipilih oleh panggilan filter()
paling awal.
Itu mungkin sedikit sedikit membingungkan, jadi semoga sebuah contoh untuk menjelaskan. Untuk memilih semua blog yang mengandungmasukan dengan "Lennon" dalam judul dan telah diterbitkan di 2008 (masukan sama memuaskan kedua keadaan), kami akan menulis:
Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
Untuk memilih semua blog yang mengandung sebuah masukan dengan "Lennon" di judul, sama halnya sebuah masukan yang telah diterbitkan di 2008, kami akan menulis:
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
Sekiranya hanya ada satu blog yang mempunyai kedua masukan mengandung "Lennon" dan masukan dari 2008 tetapi bahwa tidak satupun dari masukan dari 2008 mengandung "Lennon". Permintaan pertmana tidak akan mengembalikan blog apapun, tetapi kedua permintaan akan mengembalikan itu satu blog.
Dalam contoh kedua, penyaring pertama membatasi queryset ke semua blog-blog tersebut terkait ke masukan dengan "Lennon" di judul. Penyaring kedua membatasi kumpulan blog further ke itu yang juga terkait ke masukan yang telah diterbirkan di 2008. Masukan dipilih oleh penyaring kedua mungkin atau mungkin tidak sama seperti masukan di penyaring pertama. Kami sedang menyaring barang-barang Blog
dengan setiap pernyataan penyaring, bukan barang-barang Entry
.
Catatan
Perilaku dari filter()
untuk permintaan yang menjangkau hubungan banyak-nilai, seperti digambarkan diatas, tidak diterapkan setara untuk exclude()
. Malahan, keadaan dalam panggilan exclude()
tunggal tidak akan butuh mengacu ke barang sama.
Sebagai contoh, permintaan berikut akan tidak menyertakan blog-blog yang mengandung kedua masukan dengan "Lennon" di judul dan masukan diterbitkan di 2008:
Blog.objects.exclude(
entry__headline__contains='Lennon',
entry__pub_date__year=2008,
)
Bagaimanapun, tidak seperti perilaku ketika menggunakan filter()
,ini tidak akan membatasi blog-blog berdasarkan pada masukan yang memuaskan kedua keadaan. Untuk melakukan itu, yaitu untuk memilih semua blog yang tidak mengandung masukan diterbitkan dengan "Lennon" yang telah diterbitkan di 2008, anda butuh membuat dua permintaan:
Blog.objects.exclude(
entry__in=Entry.objects.filter(
headline__contains='Lennon',
pub_date__year=2008,
),
)
Penyaring dapat mengacu bidang pada model¶
Dalam contoh yang diberikan sejauh ini, kami telah membangun berkas-berkas penyaring yang membandingkan nilai dari bidang model dengan ketetapan. Tetapi apa jika anda ingin membandingkan nilai dai bidang model dengan bidang lain pada model sama?
Django menyediakan F expressions
untuk mengizinkan perbandingan. Instance dari F()
bertindak sebagai sebuah acuan pada model dalam permintaan. Acuan ini kemudian dapat digunakan dalam penyaring permintaan untuk membandingkan nilai-nilai dari dua bidang berbeda pada instance model sama.
Sebagai contoh, untuk menemukan daftar dari semua masukan blog yang telah mempunyai komentar lebih dari pingback, kami membangun obyek F()
untuk mengacu jumlah pingback, dan menggunakan obyek F()
itu dalam permintaan:
>>> from django.db.models import F
>>> Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks'))
Django mendukung penggunaan aritmatika penambahan, pengurangan, perkalian, pembagian modulus, dan power dengan obyek F()
, kedua dengan ketetapan dan dengan obyek F()
lain. Untuk menemukan semua masukan blog dengan lebih dari dua kali sebanyak komentar seperti pingback, kami merubah permintaan:
>>> Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks') * 2)
Untuk menemukan semua masukan dimana penilaian dari masukan sedikit dari penjumlahan hitungan pingback dan hitungan komentar, kami akan menerbitkan permintaan:
>>> Entry.objects.filter(rating__lt=F('number_of_comments') + F('number_of_pingbacks'))
Anda dapat juga menggunakan pernyataan garis bawah untuk menjangkau hubungan dalam sebuah obyek F()
. Sebuah obyek F()
dengan garis bawah ganda akan memperkenalkan join apapun dibutuhkan untuk mengakses obyek terkait. Sebagai contoh, untuk mengambil semua masukan dimana nama penulis sama seperti nama blog, kami dapat menerbitkan permintaan:
>>> Entry.objects.filter(authors__name=F('blog__name'))
Untuk bidang-bidang tanggal dan tanggal/waktu, anda dapat menambah atau mengurangi obyek timedelta
. Berikut akan mengembalikan semua masukan yang telah diubah lebih dari 3 hari setelah mereka diterbitkan.
>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
Obyek F()
mendukung tindakan bitwise dengan .bitand()`, .bitor()
, .bitrightshift()
, dan .bitleftshift()
. Sebagai contoh:
>>> F('somefield').bitand(16)
Jalan pintas pencarian pk
¶
Untuk kemudahan, Django menyediakan jalan pintas pencarian pk
, yang berdiri untuk "primary key".
Dalam contoh model Blog
, primary key adalah bidang id
, jadi pernyataan ini adalah setara:
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
>>> Blog.objects.get(pk=14) # pk implies id__exact
Penggunaan pk
tidak terbatas pada permintaan __exact
-- apapun istilah permintaan dapat dipadukan dengan pk
untuk melakukan sebuah permintaan pada primary key pada model:
# Get blogs entries with id 1, 4 and 7
>>> Blog.objects.filter(pk__in=[1,4,7])
# Get all blog entries with id > 14
>>> Blog.objects.filter(pk__gt=14)
Pencarian pk
juga bekerja liintas join. Sebagai contoh, tiga pernyataan ini adalah setara:
>>> Entry.objects.filter(blog__id__exact=3) # Explicit form
>>> Entry.objects.filter(blog__id=3) # __exact is implied
>>> Entry.objects.filter(blog__pk=3) # __pk implies __id__exact
Meloloskan tanda persen dan garis bawah dalam pernyataan LIKE
¶
Pencarian bidang yang menyerupai pernyataan SQL LIKE
(iexact
, contains
, icontains
, startswith
, istartswith
, endswith
dan iendswith
) akan otomatis meloloskan dua karakter khusus digunakan dalam pernyataan LIKE
-- tanda persen dan garis bawah. (Dalam sebuah pernyataan Like
, tanda persen menandakan wildcard banyak-karakter dan garis bawah menandakan wildcard karakter-tunggal.)
This means things should work intuitively, so the abstraction doesn't leak. For example, to retrieve all the entries that contain a percent sign, use the percent sign as any other character:
>>> Entry.objects.filter(headline__contains='%')
Django menangani dari pengutipan untuk anda; menghasilkan SQL akan mencari sesuatu seperti ini:
SELECT ... WHERE headline LIKE '%\%%';
Sama seperti garis bawah. Kedua tanda persen dan garis bawag ditangani untuk anda secara transparan.
Cache dan QuerySet
¶
Setiap QuerySet
mengandung sebuah tembolok untuk meminimalkan akses basisdata. Pahami bagaimana dia bekerja akan mengizinkan anda menulis kode paling efisien.
Dalam QuerySet
baru dibuat, cache kosong. Pertama kali sebuah QuerySet
dinilai -- dan, karena itu, sebuah permintaan basisdata terjadi -- Django menyimpan hasil permintaan dalam cache QuerySet
dan mengembalikan hasil yang telah secara jelas diminta (sebagai contoh, unsur selanjutnya, jika ada QuerySet
sedang diulang). Penilaian selanjutnya dari QuerySet
menggunakan hasil ter cache.
Jaga perilaku cache ini dalam pikiran, karena itu mungkin mengigit anda jika anda tidak menggunakan QuerySet
anda dengan benar. Sebagai contoh, berikut akan membuat dua QuerySet
, nilai mereka, dan lemparkan mereka:
>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])
Itu berarti permintaan absisdata sama akan dijalankan dua kali, berhasil menggandakan muatan basisdata anda. Juga, ada kemungkinan dua daftar mungkin tidak meneyrtakan rekaman basisdata sama, karena Entry
telah ditambahkan atau dihapus dalam pembagian kedua diantara dua permintaan.
Untuk menghindati masalah, simpan QuerySet
dan gunakan itu:
>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # Evaluate the query set.
>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.
Ketika QuerySet
tidak di cache¶
Queryset tidak selalu cache hasil mereka. Ketika menilai hanya bagian dari queryset, cache diperiksa, tetapi jika tidak dikumpulkan kemudian barang-barang dikembalikan oleh permintaan selanjutnya tidak di cache. Secara khusus, ini berarti bahwa limiting the queryset 1 menggunakan potongan senarai atau sebuah indeks tidak akan dikumpulkan cache.
Sebagi contoh, secara berulang mendapatkan indeks tertentu di queryset obyek akan meminta basisdata setiap waktu:
>>> queryset = Entry.objects.all()
>>> print(queryset[5]) # Queries the database
>>> print(queryset[5]) # Queries the database again
Bagaimanapun, jika keseluruhan queryset sudah dinilai, tembolok akan diperiksa sebagai gantinya:
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print(queryset[5]) # Uses cache
>>> print(queryset[5]) # Uses cache
Ini adalah beberapa contoh dari tindakan lain yang akan menghasilkan keseluruhan queryset yang sedang dinilai dan karena itu dikumpulkan tembolok:
>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)
Catatan
Mencetak sederhana queryset tidak akan mengumpulkan tembolok. Ini dikarenakan panggilan pada __repr__()
hanya mengembalikan potongan dari keseluruhan queryset.
Pencarian rumit dengan obyek Q
¶
Permintaan argumen katakunci -- dalam filter()
, dll. -- adalah "AND" bersama-sama. Jika anda buth menjalankan permintaan lebih rumit (sebagai contoh, permintaan dengan pernyataan OR
), anda dapat menggunakan Q objects
.
Q object
(django.db.models.Q
) adalah sebuah obyek digunakan untuk membungkus koleksi dari argumen katakunci. Argumen katakunci ini ditentukan seperti dalam "Pencarian bidang" diatas.
Sebagai contoh, obyek Q
ini membungkus permintaan LIKE
tunggal:
from django.db.models import Q
Q(question__startswith='What')
Obyek Q
dapat dipadukan menggunakan penghubung &
dan |
. Ketika sebuah penghubung digunakan pada dua obyek Q
, itu menghasilkan obyek Q
baru.
Sebagai contoh, pernyataan ini menghasilkan obyek Q
tunggal yang mewakili "OR" atau dua permintaan "question__startswith"
Q(question__startswith='Who') | Q(question__startswith='What')
Ini sama pada klausa SQL WHERE
berikut:
WHERE question LIKE 'Who%' OR question LIKE 'What%'
Anda dapat menyusun pernyataan dari kerumitan yang berubah-ubah dengan memadukan obyek Q
dengan penghubung &
and |
dan gunakan pengelompokan yang disipkan. Juga, obyek Q
dapat ditugaskan menggunakan penghubung ~
, mengizinkan perpaduan pencarian yang memadukan kedua permintaan normal dan meniadakan permintaan (NOT
):
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
Setiap fungsi pencarian yang mengambil argumen-kata kunci (sebagai contoh filter()
, exclude()
, get()
) dapat juga melewatkan satu atau lebih obyek Q
sebagai argumen (tidak-dinamai) kedudukan. Jika anda menyediakan banyak argumen obyek Q
pada fungsi pencarian, argumen akan di "AND"kan bersama-sama. Sebagai contoh:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
... kurang lebih diterjemahkan kedalam SQL:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
Fungsi pencarian dapat mencampurkan penggunaan obyek Q
dan argumen kata kunci. Semua argumen disediakan untuk fungsi pencarian (menjadi mereka argumen kata kunci atau obyek Q
) di "AND"kan bersama-sama. Bagaimanapun, jika obyek Q
disediakan, dia harus mendahului pengertian dari argumen kata kunci apapun. Sebagai contoh:
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who',
)
... akan menjadi permintaan sah, sama pada contoh sebelumnya; tetapi:
# INVALID QUERY
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
... tidak akan menjadi sah.
lihat juga
The OR lookups examples in Django's
unit tests show some possible uses of Q
.
Membandingkan obyek¶
To compare two model instances, use the standard Python comparison operator,
the double equals sign: ==
. Behind the scenes, that compares the primary
key values of two models.
Menggunakan contoh Entry
diatas, dua pernyataan berikut adalah setara:
>>> some_entry == other_entry
>>> some_entry.id == other_entry.id
Jika sebuah primary key model tidak memanggil id
, tidak masalah. Perbandingan akan selalu menggunakan primary key, apapun itu memanggilnya. Sebagai contoh, jika sebuah primary key model dipanggil name
, dua pernyataan ini adalah setara:
>>> some_obj == other_obj
>>> some_obj.name == other_obj.name
menghapus obyek¶
Untuk menghapus metode, mudah, adalah bernama delete()
. Metode ini segera menghapus obyek dan mengembalikan sejumlah obyek yang dihapus dan sebuah kamus dengan sejumlah penghapusan per jenis obyek. Contoh:
>>> e.delete()
(1, {'weblog.Entry': 1})
Anda dapat juga menghapus obyek dalam jumlah besar. Setiap QuerySet
mempunyai sebuah delete()
method, yang menghapus semua anggota dari QuerySet
tersebut.
Sebagai contoh, ini menghapus semua obyek Entry
dengan tahun pub-date
dari 2005:
>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})
Ingat bahwa ini akan, ketika memungkinkan, akan dijalankan murni dalam SQL, dan juga cara delete()
dari instance tidak akan perlu dipanggil selama pengolahan. Jika anda telah menyediakan cara delete()
disesuaikan pada sebuah kelas model dan ingin memastikan bahwa dia dipanggil, anda akan butuh "secara manual" menghapus instance dari model tersebut (sebagai contoh, dengan perulangan terhadap QuerySet
dan memanggil delete()
pada setiap obyek secara tersendiri) daripada menggunakan dalam jumlah besar cara delete()
dari sebuah QuerySet
.
Ketika DJANGO menghapus sebuah obyek, secara awal dia meniru kebiasaan batasan SQL ON DELETE CASCADE
-- dalam kata lain, obyek apapun yang mempunyai foreign key menunjuk pada obyek yang akan dihapus akan dihapus bersama dengannya. Sebagai contoh:
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()
Kebiasaan turunan ini dapat di sesuaikan melalui argumen on_delete
ke ForeignKey
.
Catat bahwa delete()
adalah hanya cara QuerySet
yang tidak ditunjukkan pada Manager
itu sendiri. Ini adalah mekanisme aman untuk mencegah anda dari kecelakaan permintaan Entry.objects.delete()
, dan menghapus semua masukan. Jika anda ingin melakukan menghapus semua obyek, kemudian anda harus secara jelas meminta kumpulan permintaan lengkap:
Entry.objects.all().delete()
Menyalin instance model¶
Although there is no built-in method for copying model instances, it is
possible to easily create new instance with all fields' values copied. In the
simplest case, you can set pk
to None
. Using our blog example:
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
Hal-hal dapat lebih rumit jika anda menggunakan warisan. Pertimbangkan subkelas dari Blog
:
class ThemeBlog(Blog):
theme = models.CharField(max_length=200)
django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
django_blog.save() # django_blog.pk == 3
Disebabkan oleh bagaimana warisan bekerja, anda harus menyetel kedua pk
dan id
menjadi None:
django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4
Pengolahan ini tidak menyalin hubungan yang bukan bagian dari tabel basisdata model. Sebagai contoh, Entry
mempunyai ManyToManyField
terhadap Author
. Setelah menggandakan sebuah masukan, anda harus menyetel hubungan many-to-many untuk masukan baru:
entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors.set(old_authors)
Untuk OneToOneField
, anda harus menggandakan obyek terkait dan memberikan itu ke bidang obyek baru untuk menghindari melanggar batasan untuk one-to-one. Sebagai contoh, menganggap entry
sudah digandakan seperti diatas:
detail = EntryDetail.objects.all()[0]
detail.pk = None
detail.entry = entry
detail.save()
Memperbaharui banyak obyek sekaligus¶
Terkadang anda ingin menyetel sebuah bidang ke nilai tertentu untuk semua obyek dalam QuerySet
. Anda dapat melakukan ini dengan cara update()
. Sebagai contoh:
# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
Anda dapat hanya menyetel bidang-bidang bukan-hubungan dan bidang-bidang ForeignKey
menggunakan metode ini. Untuk memperbaharui bidang-bidang ForeignKey
, setel nilai baru ke instance model baru anda ingin tunjuk. Sebagai contoh:
>>> b = Blog.objects.get(pk=1)
# Change every Entry so that it belongs to this Blog.
>>> Entry.objects.all().update(blog=b)
Metode update()
diberlakukan segera dan mengembalikan sejumlah baris cocok oleh permintaan (yang mungkin tidak setara pada sejumlah baris diperbaharui jika baris sudah mempunyai nilai baru). Hanya batasan pada QuerySet
sedang diperbaharui adalah itu dapat hanya diakses pada tabel basisdata: tabel utama model. Anda dapat menyaring pada bidang-bidang terkait, tetapi anda dapat hanya memperbaharui kolom dalam tabel utama model. Contoh:
>>> b = Blog.objects.get(pk=1)
# Update all the headlines belonging to this Blog.
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')
Be aware that the update()
method is converted directly to an SQL
statement. It is a bulk operation for direct updates. It doesn't run any
save()
methods on your models, or emit the
pre_save
or post_save
signals (which are a consequence of calling
save()
), or honor the
auto_now
field option.
If you want to save every item in a QuerySet
and make sure that the save()
method is called on
each instance, you don't need any special function to handle that. Loop over
them and call save()
:
for item in my_queryset:
item.save()
Panggilan untuk memperbaharui juga menggunakan F expressions
untuk memperbaharui satu bidang berdasarkan pada nilai dari bidang lain dalam model. Ini adalah khususnya berguna untuk meningkatkan hitungan berdasarkan pada nilai saat ini mereka. Sebagai contoh, untuk menaikkan hitungan pingback untuk setiap masukan dalam blog:
>>> Entry.objects.all().update(number_of_pingbacks=F('number_of_pingbacks') + 1)
Bagaimanapun, tidak seperti obyek F()
dalam penyaringan dan tidak menyertakan klausa-klausa, anda tidak dapat memperkenalkan penggabungan ketika anda menggunakan obyek F()
dalam sebuah pembaharuan -- anda hanya dapat mengacu bidang-bidang lokal ke model sedang diperbaharui. Jika anda berusaha memperkenalkan penggabungan dengan sebuah obyek F()
, sebuah FieldError
akan dimunculkan:
# This will raise a FieldError
>>> Entry.objects.update(headline=F('blog__name'))
Kembali ke mentah SQL¶
Jika anda menemukan anda sendiri butuh menulis permintaan SQL yang terlalu rumit untuk pemetaan-basisdata Django untuk ditangani, anda dapat kembali menulis SQL dengan tangan. Django mempunyai sepasang pilihan untuk menulis permintaan SQL mentah; lihat Melakukan permintaan SQL mentah.
Akhirnya, itu penting dicatat bahwa lapisan basisdata Django hanya antarmuka ke basisdata anda. Anda dapat mengakses basisdata anda melalui alat-alat lain, bahasa pemrograman atau kerangka basisdata; tidak ada spesifik-Django tentang basisdata anda.