Untuk menentukan hubungan many-to-one, gunakan ForeignKey
:
from django.db import models
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self): # __unicode__ on Python 2
return "%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self): # __unicode__ on Python 2
return self.headline
class Meta:
ordering = ('headline',)
Apa yang mengikuti adalah contoh-contoh dari tindakan yang dapat dilakukan menggunakan fasilitas API Python.
Buat sedikir Reporter:
>>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r.save()
>>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
>>> r2.save()
Buat sebuah Artikel:
>>> from datetime import date
>>> a = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27), reporter=r)
>>> a.save()
>>> a.reporter.id
1
>>> a.reporter
<Reporter: John Smith>
Catat bahwa anda harus menyimpan sebuah obyek sebelum itu dapat diberikan ke hubungan foreign key. Sebagai contoh, membuat Article
dengan Reporter
tidak disimpan memunculkan ValueError
:
>>> r3 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> Article.objects.create(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r3)
Traceback (most recent call last):
...
ValueError: save() prohibited to prevent data loss due to unsaved related object 'reporter'.
Obyek artikel mempunyai akses ke obyek Reporter terkait:
>>> r = a.reporter
Pada Python 2, ini adalah string dari jenis str
daripada string unicode karena itulah yang apa telah digunakan dalam pembuatan dari pelapor (dan kami belum menyegarkan data dari basisdata, yang selalu mengembalikan string unicode):
>>> r.first_name, r.last_name
('John', 'Smith')
Buat sebuah Article melalui obyek Reporter:
>>> new_article = r.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29))
>>> new_article
<Article: John's second story>
>>> new_article.reporter
<Reporter: John Smith>
>>> new_article.reporter.id
1
Buat sebuah artikel, dan tambah itu ke kumpulan artikel:
>>> new_article2 = Article(headline="Paul's story", pub_date=date(2006, 1, 17))
>>> r.article_set.add(new_article2)
>>> new_article2.reporter
<Reporter: John Smith>
>>> new_article2.reporter.id
1
>>> r.article_set.all()
<QuerySet [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]>
Tambah artikel sama ke kumpulan artikel berbeda - periksa bahwa itu berpindah:
>>> r2.article_set.add(new_article2)
>>> new_article2.reporter.id
2
>>> new_article2.reporter
<Reporter: Paul Jones>
Menambahkan sebuah obyek dari jenis salah memunculkan TypeError:
>>> r.article_set.add(r2)
Traceback (most recent call last):
...
TypeError: 'Article' instance expected
>>> r.article_set.all()
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> r2.article_set.all()
<QuerySet [<Article: Paul's story>]>
>>> r.article_set.count()
2
>>> r2.article_set.count()
1
Catat bahwa di contoh terakhir artikel telah dipindahkan dari John ke Paul.
Pengelola terkait mendukung pencarian bidang-bidang juga. API otomatis mengikuti hubungan sejauh anda butuhkan. Gunakan garis bawah ganda untuk memisahkan hubungan. Ini bekerja sebanyak tingkatan yang anda inginkan. Tidak ada batasan. Sebagai contoh:
>>> r.article_set.filter(headline__startswith='This')
<QuerySet [<Article: This is a test>]>
# Find all Articles for any Reporter whose first name is "John".
>>> Article.objects.filter(reporter__first_name='John')
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
Benar-benar cocok tersirat disini:
>>> Article.objects.filter(reporter__first_name='John')
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
Permintaan dua kali lebih bidang terkait. Ini menterjemahkan pada sebuah keadaan AND dalam klausa WHERE:
>>> Article.objects.filter(reporter__first_name='John', reporter__last_name='Smith')
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
Untuk pencarian terkait anda dapat menyediakan sebuah nilai primary key atau lewatkan obyek terkait dengan tegas:
>>> Article.objects.filter(reporter__pk=1)
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> Article.objects.filter(reporter=1)
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> Article.objects.filter(reporter=r)
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> Article.objects.filter(reporter__in=[1,2]).distinct()
<QuerySet [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]>
>>> Article.objects.filter(reporter__in=[r,r2]).distinct()
<QuerySet [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]>
Anda dapat juga menggunakan queryset daripada daftar harfiah dari instance:
>>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinct()
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
Meminta di arah berlawanan:
>>> Reporter.objects.filter(article__pk=1)
<QuerySet [<Reporter: John Smith>]>
>>> Reporter.objects.filter(article=1)
<QuerySet [<Reporter: John Smith>]>
>>> Reporter.objects.filter(article=a)
<QuerySet [<Reporter: John Smith>]>
>>> Reporter.objects.filter(article__headline__startswith='This')
<QuerySet [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]>
>>> Reporter.objects.filter(article__headline__startswith='This').distinct()
<QuerySet [<Reporter: John Smith>]>
Menghitung dalam arah berlawanan bekerja dalam hubungan dengan distinct():
>>> Reporter.objects.filter(article__headline__startswith='This').count()
3
>>> Reporter.objects.filter(article__headline__startswith='This').distinct().count()
1
Permintaan dapat berputar seperti lingkaran:
>>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
<QuerySet [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]>
>>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
<QuerySet [<Reporter: John Smith>]>
>>> Reporter.objects.filter(article__reporter=r).distinct()
<QuerySet [<Reporter: John Smith>]>
Jika anda menghapus sebuah reporter, artikel dia akan dihapus (menganggap bahwa ForeignKey telah ditentukan dengan django.db.models.ForeignKey.on_delete
setel menjadi CASCADE
, yang merupakan awalan):
>>> Article.objects.all()
<QuerySet [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]>
>>> Reporter.objects.order_by('first_name')
<QuerySet [<Reporter: John Smith>, <Reporter: Paul Jones>]>
>>> r2.delete()
>>> Article.objects.all()
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> Reporter.objects.order_by('first_name')
<QuerySet [<Reporter: John Smith>]>
Anda dapat menghapus menggunakan JOIN di permintaan:
>>> Reporter.objects.filter(article__headline__startswith='This').delete()
>>> Reporter.objects.all()
<QuerySet []>
>>> Article.objects.all()
<QuerySet []>
Apr 04, 2017