参考文献:
https://docs.djangoproject.com/zh-hans/2.0/
http://www.cnblogs.com/yuanchenqi/articles/6083427.html
字段
.choices:
1 from django.db import models 2 3 class Person(models.Model): 4 SHIRT_SIZES = ( 5 ('S', 'Small'), 6 ('M', 'Medium'), 7 ('L', 'Large'), 8 ) 9 name = models.CharField(max_length=60) 10 shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) 11 12 13 >>> p = Person(name="Fred Flintstone", shirt_size="L") 14 >>> p.save() 15 >>> p.shirt_size 16 'L' 17 >>> p.get_shirt_size_display() 18 'Large'
数据库中的三种关系:多对一、多对多、一对一
.Many-to-one relationships(Foreignkey)
模型建立:
其中ForeignKey的字段一般为所关联对象的小写
1 from django.db import models 2 3 class Reporter(models.Model): 4 first_name = models.CharField(max_length=30) 5 last_name = models.CharField(max_length=30) 6 email = models.EmailField() 7 8 def __str__(self): 9 return "%s %s" % (self.first_name, self.last_name) 10 11 class Article(models.Model): 12 headline = models.CharField(max_length=100) 13 pub_date = models.DateField() 14 reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE) 15 16 def __str__(self): 17 return self.headline 18 19 class Meta: 20 ordering = ('headline',)
创建Reportes:
1 >>> r = Reporter(first_name='John', last_name='Smith', email='[email protected]') 2 >>> r.save() 3 4 >>> r2 = Reporter(first_name='Paul', last_name='Jones', email='[email protected]') 5 >>> r2.save()
创建Article:
>>> 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>
通过Reporters反向创建Article对象:
1 >>> new_article = r.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29)) 2 >>> new_article 3 <Article: John's second story> 4 >>> new_article.reporter 5 <Reporter: John Smith> 6 >>> new_article.reporter.id 7 1
创建一个Article对象,并添加到r的article_set中:
>>> new_article2 = Article.objects.create(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>]>
将同一个Article对象,添加到r2的article_set中,此时它会移动到新的article_set中,也就是指向新的Reporters:
View Code
成员间的交叉查询:
>>> 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>]>
多条件查询,中间用“,”隔开,相当于and操作:
>>> Article.objects.filter(reporter__first_name='John', reporter__last_name='Smith') <QuerySet [<Article: John's second story>, <Article: This is a test>]>
通过主键或者对象,进行直接查询操作:
>>> 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>]>
使用queryset进行嵌套查询:
>>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinct() <QuerySet [<Article: John's second story>, <Article: This is a test>]>
反向查询:
>>> 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>]>
级联查询:
>>> Reporter.objects.filter(article__headline__startswith='This').count() 3 >>> Reporter.objects.filter(article__headline__startswith='This').distinct().count() 1
多次循环查询:
>>> 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>]>
当在定义外键的时候,on_delete=models.CASCADE,删除的时候会级联删除:
>>> 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>]>
>>> Reporter.objects.filter(article__headline__startswith='This').delete() >>> Reporter.objects.all() <QuerySet []> >>> Article.objects.all() <QuerySet []>
.Many-to-many relationships
模型建立:
其中ManyToManyField字段的变量名一般为所关联的对象的小写,并以复数的形式
class Publication(models.Model): title = models.CharField(max_length=30) def __str__(self): return self.title class Meta: ordering = ('title',) class Article(models.Model): headline = models.CharField(max_length=100) publications = models.ManyToManyField(Publication) def __str__(self): return self.headline class Meta: ordering = ('headline',)
创建多个Publication对象:
>>> p1 = Publication(title='The Python Journal') >>> p1.save() >>> p2 = Publication(title='Science News') >>> p2.save() >>> p3 = Publication(title='Science Weekly') >>> p3.save()
创建一个Article对象:
>>> a1 = Article(headline='Django lets you build Web apps easily') >>> a1.save()
将Article关联到Publication:
>>> a1.publications.add(p1)
创建新的Article对象,并关联Publication,(注意,这里可以关联之前被其他Article对象关联过的Publication,所以这是一个多对多的关系):
>>> a2 = Article(headline='NASA uses Python') >>> a2.save() >>> a2.publications.add(p1, p2) >>> a2.publications.add(p3)
重复关联也没问题,django会自动忽略,并不会重复创建同样的关系:
>>> a2.publications.add(p3)
一步创建:
>>> new_publication = a2.publications.create(title='Highlights for Children')
Article正向查询:
>>> a1.publications.all() <QuerySet [<Publication: The Python Journal>]> >>> a2.publications.all() <QuerySet [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]>
Publication反向查询:
>>> p2.article_set.all() <QuerySet [<Article: NASA uses Python>]> >>> p1.article_set.all() <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]> >>> Publication.objects.get(id=4).article_set.all() <QuerySet [<Article: NASA uses Python>]>
多对多关系的查询:
>>> Article.objects.filter(publications__id=1) <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]> >>> Article.objects.filter(publications__pk=1) <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]> >>> Article.objects.filter(publications=1) <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]> >>> Article.objects.filter(publications=p1) <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]> >>> Article.objects.filter(publications__title__startswith="Science") <QuerySet [<Article: NASA uses Python>, <Article: NASA uses Python>]> >>> Article.objects.filter(publications__title__startswith="Science").distinct() <QuerySet [<Article: NASA uses Python>]>
count和discount函数的使用:
>>> Article.objects.filter(publications__title__startswith="Science").count() 2 >>> Article.objects.filter(publications__title__startswith="Science").distinct().count() 1 >>> Article.objects.filter(publications__in=[1,2]).distinct() <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]> >>> Article.objects.filter(publications__in=[p1,p2]).distinct() <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]>
Publications的查询:
>>> Publication.objects.filter(id=1) <QuerySet [<Publication: The Python Journal>]> >>> Publication.objects.filter(pk=1) <QuerySet [<Publication: The Python Journal>]> >>> Publication.objects.filter(article__headline__startswith="NASA") <QuerySet [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]> >>> Publication.objects.filter(article__id=1) <QuerySet [<Publication: The Python Journal>]> >>> Publication.objects.filter(article__pk=1) <QuerySet [<Publication: The Python Journal>]> >>> Publication.objects.filter(article=1) <QuerySet [<Publication: The Python Journal>]> >>> Publication.objects.filter(article=a1) <QuerySet [<Publication: The Python Journal>]> >>> Publication.objects.filter(article__in=[1,2]).distinct() <QuerySet [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]> >>> Publication.objects.filter(article__in=[a1,a2]).distinct() <QuerySet [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>, <Publication: The Python Journal>]>
Excludes的使用:
>>> Article.objects.exclude(publications=p2)
<QuerySet [<Article: Django lets you build Web apps easily>]>
Publications删除后,对应的Article无法获取原先的Publication:
>>> p1.delete() >>> Publication.objects.all() <QuerySet [<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science Weekly>]> >>> a1 = Article.objects.get(pk=1) >>> a1.publications.all() <QuerySet []>
Article删除后,Publications也无法获取Article对象:
>>> a2.delete() >>> Article.objects.all() <QuerySet [<Article: Django lets you build Web apps easily>]> >>> p2.article_set.all() <QuerySet []>
通过第三方添加多对多关系:
>>> a4 = Article(headline='NASA finds intelligent life on Earth') >>> a4.save() >>> p2.article_set.add(a4) >>> p2.article_set.all() <QuerySet [<Article: NASA finds intelligent life on Earth>]> >>> a4.publications.all() <QuerySet [<Publication: Science News>]>
通过关键字添加:
>>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders') >>> p2.article_set.all() <QuerySet [<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]> >>> a5 = p2.article_set.all()[1] >>> a5.publications.all() <QuerySet [<Publication: Science News>]>
通过Article来删除指向Article的Publications对象:
>>> a4.publications.remove(p2) >>> p2.article_set.all() <QuerySet [<Article: Oxygen-free diet works wonders>]> >>> a4.publications.all() <QuerySet []>
通过Publication来删除指定的Article对象:
>>> p2.article_set.remove(a5) >>> p2.article_set.all() <QuerySet []> >>> a5.publications.all() <QuerySet []>
设置关系:
>>> a4.publications.all() <QuerySet [<Publication: Science News>]> >>> a4.publications.set([p3]) >>> a4.publications.all() <QuerySet [<Publication: Science Weekly>]>
清除关系:
>>> p2.article_set.clear() >>> p2.article_set.all() <QuerySet []>
从另一端清除关系:
>>> p2.article_set.add(a4, a5) >>> p2.article_set.all() <QuerySet [<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>]> >>> a4.publications.all() <QuerySet [<Publication: Science News>, <Publication: Science Weekly>]> >>> a4.publications.clear() >>> a4.publications.all() <QuerySet []> >>> p2.article_set.all() <QuerySet [<Article: Oxygen-free diet works wonders>]>
重新创建:
>>> p1 = Publication(title='The Python Journal') >>> p1.save() >>> a2 = Article(headline='NASA uses Python') >>> a2.save() >>> a2.publications.add(p1, p2, p3)
指定删除:
>>> Publication.objects.filter(title__startswith='Science').delete() >>> Publication.objects.all() <QuerySet [<Publication: Highlights for Children>, <Publication: The Python Journal>]> >>> Article.objects.all() <QuerySet [<Article: Django lets you build Web apps easily>, <Article: NASA finds intelligent life on Earth>, <Article: NASA uses Python>, <Article: Oxygen-free diet works wonders>]> >>> a2.publications.all() <QuerySet [<Publication: The Python Journal>]>
整块删除:
>>> q = Article.objects.filter(headline__startswith='Django') >>> print(q) <QuerySet [<Article: Django lets you build Web apps easily>]> >>> q.delete()
>>> print(q) <QuerySet []> >>> p1.article_set.all() <QuerySet [<Article: NASA uses Python>]>
复杂的多对多关联关系,通过through字段来定义:
模型:
class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): return self.name class Membership(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
创建对象:
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason="Needed a new drummer.") >>> m1.save() >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>]> >>> ringo.group_set.all() <QuerySet [<Group: The Beatles>]> >>> m2 = Membership.objects.create(person=paul, group=beatles, ... date_joined=date(1960, 8, 1), ... invite_reason="Wanted to form a band.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
增加,删除对象都不能用常规的add()、create()、set()方法。因为这些方法没法把关系说明确。
常规的remove()方法也不行。如下所示:
>>> Membership.objects.create(person=ringo, group=beatles, ... date_joined=date(1968, 9, 4), ... invite_reason="You've been gone for a month and we miss you.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]> >>> # This will not work because it cannot tell which membership to remove >>> beatles.members.remove(ringo)
但可以使用clear()方法,如下所示:
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() <QuerySet []>
查询操作:# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul') <QuerySet [<Group: The Beatles>]>
If you need to access a membership's information you may do so by directly querying theMembership
model:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo) >>> ringos_membership.date_joined datetime.date(1962, 8, 16) >>> ringos_membership.invite_reason 'Needed a new drummer.'
Another way to access the same information is by querying the many-to-many reverse relationship from aPerson
object:
>>> ringos_membership = ringo.membership_set.get(group=beatles) >>> ringos_membership.date_joined datetime.date(1962, 8, 16) >>> ringos_membership.invite_reason 'Needed a new drummer.'
.One-to-one relationships
模型建立:
class Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) def __str__(self): return "%s the place" % self.name class Restaurant(models.Model): place = models.OneToOneField( Place, on_delete=models.CASCADE, primary_key=True, ) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False) def __str__(self): return "%s the restaurant" % self.place.name class Waiter(models.Model): restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE) name = models.CharField(max_length=50) def __str__(self): return "%s the waiter at %s" % (self.name, self.restaurant)
创建Place对象:
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') >>> p1.save() >>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland') >>> p2.save()
创建Restaurant对象:
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
正向查询:
>>> r.place
<Place: Demon Dogs the place>
反向查询:
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
如果差不到,则会引发异常:
>>> from django.core.exceptions import ObjectDoesNotExist >>> try: >>> p2.restaurant >>> except ObjectDoesNotExist: >>> print("There is no restaurant here.") There is no restaurant here.
可以使用 hasattr 来判断:
>>> hasattr(p2, 'restaurant') False
设置操作:
>>> r.place = p2 >>> r.save() >>> p2.restaurant <Restaurant: Ace Hardware the restaurant> >>> r.place <Place: Ace Hardware the place>
反向设置:
>>> p1.restaurant = r >>> p1.restaurant <Restaurant: Demon Dogs the restaurant>
查询操作:
>>> Restaurant.objects.all()
<QuerySet [<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>]>
Places查询会返回所有的Place,不管是否已经绑定Restaurant:
>>> Place.objects.order_by('name') <QuerySet [<Place: Ace Hardware the place>, <Place: Demon Dogs the place>]>
Restaurant对象正向查询:
>>> Restaurant.objects.get(place=p1) <Restaurant: Demon Dogs the restaurant> >>> Restaurant.objects.get(place__pk=1) <Restaurant: Demon Dogs the restaurant> >>> Restaurant.objects.filter(place__name__startswith="Demon") <QuerySet [<Restaurant: Demon Dogs the restaurant>]> >>> Restaurant.objects.exclude(place__address__contains="Ashland") <QuerySet [<Restaurant: Demon Dogs the restaurant>]>
Places对象反向查询:
>>> Place.objects.get(pk=1) <Place: Demon Dogs the place> >>> Place.objects.get(restaurant__place=p1) <Place: Demon Dogs the place> >>> Place.objects.get(restaurant=r) <Place: Demon Dogs the place> >>> Place.objects.get(restaurant__place__name__startswith="Demon") <Place: Demon Dogs the place>
给Restaurant对象添加Waiter:
>>> w = r.waiter_set.create(name='Joe') >>> w <Waiter: Joe the waiter at Demon Dogs the restaurant>
查询waiters:
>>> Waiter.objects.filter(restaurant__place=p1) <QuerySet [<Waiter: Joe the waiter at Demon Dogs the restaurant>]> >>> Waiter.objects.filter(restaurant__place__name__startswith="Demon") <QuerySet [<Waiter: Joe the waiter at Demon Dogs the restaurant>]>
可以通过引入另外的app数据库,来关联:
from django.db import models from geography.models import ZipCode class Restaurant(models.Model): # ... zip_code = models.ForeignKey( ZipCode, on_delete=models.SET_NULL, blank=True, null=True, )