123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- #########################
- Many-to-one relationships
- #########################
- .. highlight:: pycon
- To define a many-to-one relationship, use :class:`~django.db.models.ForeignKey`.
- .. code-block:: python
- 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 __unicode__(self):
- return u"%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)
- def __unicode__(self):
- return self.headline
- class Meta:
- ordering = ('headline',)
- What follows are examples of operations that can be performed using the Python
- API facilities.
- Create a few Reporters::
- >>> 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()
- Create an Article::
- >>> from datetime import datetime
- >>> a = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporter=r)
- >>> a.save()
- >>> a.reporter.id
- 1
- >>> a.reporter
- <Reporter: John Smith>
- Article objects have access to their related Reporter objects::
- >>> r = a.reporter
- These are strings instead of unicode strings because that's what was used in
- the creation of this reporter (and we haven't refreshed the data from the
- database, which always returns unicode strings)::
- >>> r.first_name, r.last_name
- ('John', 'Smith')
- Create an Article via the Reporter object::
- >>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(2005, 7, 29))
- >>> new_article
- <Article: John's second story>
- >>> new_article.reporter
- <Reporter: John Smith>
- >>> new_article.reporter.id
- 1
- Create a new article, and add it to the article set::
- >>> new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17))
- >>> r.article_set.add(new_article2)
- >>> new_article2.reporter
- <Reporter: John Smith>
- >>> new_article2.reporter.id
- 1
- >>> r.article_set.all()
- [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
- Add the same article to a different article set - check that it moves::
- >>> r2.article_set.add(new_article2)
- >>> new_article2.reporter.id
- 2
- >>> new_article2.reporter
- <Reporter: Paul Jones>
- Adding an object of the wrong type raises TypeError::
- >>> r.article_set.add(r2)
- Traceback (most recent call last):
- ...
- TypeError: 'Article' instance expected
- >>> r.article_set.all()
- [<Article: John's second story>, <Article: This is a test>]
- >>> r2.article_set.all()
- [<Article: Paul's story>]
- >>> r.article_set.count()
- 2
- >>> r2.article_set.count()
- 1
- Note that in the last example the article has moved from John to Paul.
- Related managers support field lookups as well.
- The API automatically follows relationships as far as you need.
- Use double underscores to separate relationships.
- This works as many levels deep as you want. There's no limit. For example::
- >>> r.article_set.filter(headline__startswith='This')
- [<Article: This is a test>]
- # Find all Articles for any Reporter whose first name is "John".
- >>> Article.objects.filter(reporter__first_name__exact='John')
- [<Article: John's second story>, <Article: This is a test>]
- Exact match is implied here::
- >>> Article.objects.filter(reporter__first_name='John')
- [<Article: John's second story>, <Article: This is a test>]
- Query twice over the related field. This translates to an AND condition in the
- WHERE clause::
- >>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith')
- [<Article: John's second story>, <Article: This is a test>]
- For the related lookup you can supply a primary key value or pass the related
- object explicitly::
- >>> Article.objects.filter(reporter__pk=1)
- [<Article: John's second story>, <Article: This is a test>]
- >>> Article.objects.filter(reporter=1)
- [<Article: John's second story>, <Article: This is a test>]
- >>> Article.objects.filter(reporter=r)
- [<Article: John's second story>, <Article: This is a test>]
- >>> Article.objects.filter(reporter__in=[1,2]).distinct()
- [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
- >>> Article.objects.filter(reporter__in=[r,r2]).distinct()
- [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
- You can also use a queryset instead of a literal list of instances::
- >>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinct()
- [<Article: John's second story>, <Article: This is a test>]
- Querying in the opposite direction::
- >>> Reporter.objects.filter(article__pk=1)
- [<Reporter: John Smith>]
- >>> Reporter.objects.filter(article=1)
- [<Reporter: John Smith>]
- >>> Reporter.objects.filter(article=a)
- [<Reporter: John Smith>]
- >>> Reporter.objects.filter(article__headline__startswith='This')
- [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
- >>> Reporter.objects.filter(article__headline__startswith='This').distinct()
- [<Reporter: John Smith>]
- Counting in the opposite direction works in conjunction with distinct()::
- >>> Reporter.objects.filter(article__headline__startswith='This').count()
- 3
- >>> Reporter.objects.filter(article__headline__startswith='This').distinct().count()
- 1
- Queries can go round in circles::
- >>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
- [<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
- >>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
- [<Reporter: John Smith>]
- >>> Reporter.objects.filter(article__reporter__exact=r).distinct()
- [<Reporter: John Smith>]
- If you delete a reporter, his articles will be deleted (assuming that the
- ForeignKey was defined with :attr:`django.db.models.ForeignKey.on_delete` set to
- ``CASCADE``, which is the default)::
- >>> Article.objects.all()
- [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
- >>> Reporter.objects.order_by('first_name')
- [<Reporter: John Smith>, <Reporter: Paul Jones>]
- >>> r2.delete()
- >>> Article.objects.all()
- [<Article: John's second story>, <Article: This is a test>]
- >>> Reporter.objects.order_by('first_name')
- [<Reporter: John Smith>]
- You can delete using a JOIN in the query::
- >>> Reporter.objects.filter(article__headline__startswith='This').delete()
- >>> Reporter.objects.all()
- []
- >>> Article.objects.all()
- []
|