from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): # __unicode__ on Python 2 return self.name class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() def __str__(self): # __unicode__ on Python 2 return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __str__(self): # __unicode__ on Python 2 return self.headline
反向查询¶
如果模型I有一个ForeignKey,那么该ForeignKey 所指的模型II实例可以通过一个管理器返回前面有ForeignKey的模型I的所有实例。默认情况下,这个管理器的名字为foo_set,其中foo 是源模型的小写名称。该管理器返回的查询集可以用上一节提到的方式进行过滤和操作。
例如:
>>> b = Blog.objects.get(id=1) >>> b.entry_set.all() # Returns all Entry objects related to Blog. # b.entry_set is a Manager that returns QuerySets. >>> b.entry_set.filter(headline__contains='Lennon') >>> b.entry_set.count()
你可以在ForeignKey 定义时设置related_name 参数来覆盖foo_set 的名称。例如,如果Entry 模型改成blog =ForeignKey(Blog, related_name='entries'),那么上面的示例代码应该改成这样:
>>> b = Blog.objects.get(id=1) >>> b.entries.all() # Returns all Entry objects related to Blog. # b.entries is a Manager that returns QuerySets. >>> b.entries.filter(headline__contains='Lennon') >>> b.entries.count()
处理关联对象的其它方法¶
除了在上面”获取对象“一节中定义的查询集 方法之外,ForeignKey 管理器 还有其它方法用于处理关联的对象集合。下面是每个方法的大概,完整的细节可以在关联对象参考 中找到。
add(obj1, obj2, ...)
添加一指定的模型对象到关联的对象集中。
create(**kwargs)
创建一个新的对象,将它保存并放在关联的对象集中。返回新创建的对象。
remove(obj1, obj2, ...)
从关联的对象集中删除指定的模型对象。
clear()
从关联的对象集中删除所有的对象。
若要一次性给关联的对象集赋值,只需要给它赋值一个可迭代的对象。这个可迭代的对象可以包含对象的实例,或者一个主键值的列表。例如:
b = Blog.objects.get(id=1) b.entry_set = [e1, e2]
在这个例子中,e1 和e2 可以是Entry 实例,也可以是主键的整数值。
如果有clear() 方法,那么在将可迭代对象中的成员添加到集合中之前,将从entry_set 中删除所有已经存在的对象。如果没有clear() 方法,那么将直接添加可迭代对象中的成员而不会删除所有已存在的对象。
这一节中提到的每个”反向“操作都会立即对数据库产生作用。每个添加、创建和删除操作都会立即并自动保存到数据库中。
多对多关系¶
多对多关系的两端都会自动获得访问另一端的API。这些API 的工作方式与上面提到的“方向”一对多关系一样。
唯一的区别在于属性的名称:定义 ManyToManyField 的模型使用该字段的属性名称,而“反向”模型使用源模型的小写名称加上'_set'(和一对多关系一样)。
一个例子可以让它更好理解:
e = Entry.objects.get(id=3) e.authors.all() # Returns all Author objects for this Entry. e.authors.count() e.authors.filter(name__contains='John') a = Author.objects.get(id=5) a.entry_set.all() # Returns all Entry objects for this Author.
类似ForeignKey,ManyToManyField 可以指定related_name。在上面的例子中,如果Entry 中的ManyToManyField 指定related_name='entries',那么Author 实例将使用 entries 属性而不是entry_set。
一对一关系¶
一对一关系与多对一关系非常相似。如果你在模型中定义一个OneToOneField,该模型的实例将可以通过该模型的一个简单属性访问关联的模型。
例如:
class EntryDetail(models.Model): entry = models.OneToOneField(Entry) details = models.TextField() ed = EntryDetail.objects.get(id=2) ed.entry # Returns the related Entry object.
在“反向”查询中有所不同。一对一关系中的关联模型同样具有一个管理器对象,但是该管理器表示一个单一的对象而不是对象的集合:
e = Entry.objects.get(id=2) e.entrydetail # returns the related EntryDetail object
如果没有对象赋值给这个关联关系,Django 将引发一个DoesNotExist 异常。
实例可以赋值给反向的关联关系,方法和正向的关联关系一样:
e.entrydetail = ed