django-model外键关系之一对多
一对多
外键字段是放在多的一方模型类里面的
比如,一辆汽车(Car)有一个制造商(Manufacturer) —— 但是一个制造商(Manufacturer) 生产很多汽车(Car),每一辆汽车(Car) 只能有一个制造商(Manufacturer) —— 使用下面的定义:
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
company_that_makes_it = models.ForeignKey(Manufacturer)
如果想要创建和自己关联的一对多关系,使用self指向自己
models.ForeignKey('self')
一对多的使用和绑定
准备数据
比如有下面两个模型类
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)
def __str__(self): # __unicode__ on Python 2
return self.headline
class Meta:
ordering = ('headline',)
关联对象
默认方式
# 创建几个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()
#创建一个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>
# 注意,将对象分配给一个外键之前必须保存。例如,使用未保存的Reporter 创建Article 将引发ValueError:
>>> r3 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> Article(headline="This is a test", pub_date=date(2005, 7, 27), reporter=r3)
Traceback (most recent call last):
...
ValueError: 'Cannot assign "<Reporter: John Smith>": "Reporter" instance isn't saved in the database.'
#访问关联对象,具体看模型的查询
>>> r = a.reporter
>>> r.first_name, r.last_name
('John', 'Smith')
除了上面的方式外还有几个内建的关联对象的方法,add,create,remove,clear
-
add(obj1, obj2, ...)添加一指定的模型对象到关联的对象集中。
>>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r1.save()
>>> a1 = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27))
>>> a1.save()
>>> r1.article_set.add(a1) -
create(**kwargs)创建一个新的对象,将它保存并放在关联的对象集中。返回新创建的对象。
>>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r1.save()
>>> r1.article_set.create(headline="This is a test", pub_date=date(2005, 7, 27)) -
remove(obj1, obj2, ...)从关联的对象集中删除指定的模型对象。
>>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r1.save()
>>> r1.article_set.create(headline="This is a test", pub_date=date(2005, 7, 27))
>>> a1 = Article.objects.filter(id=1)
>>> r1.article_set.remove(a1) -
clear()从关联的对象集中删除所有的对象。
>>> r1 = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r1.save()
>>> r1.article_set.create(headline="This is a test", pub_date=date(2005, 7, 27))
>>> r1.article_set.clear() -
一次性关联多个对象
若要一次性给关联的对象集赋值,只需要给它赋值一个可迭代的对象。这个可迭代的对象可以包含对象的实例,或者一个主键值的列表。
>>> r1 = Reporter.objects.get(id=1)
>>> r1.entry_set = [a1, a2]
a1 和a2 可以是Article 实例,也可以是Article实例主键的整数值。
外键关联对象的查找(或者说是索引也可以说是获取)或者说是关联模型的反向查询
比如有两个模型类A和B,A是多的一方,B是一的一方,外键字段是设置在多的一方里面的
-
使用默认方式(源模型名__set方式) 源模型名要小写
class A(models.Model):
age = models.IntField()
obj_b = models.ForeignKey(B)class B(modes.Model):
name = models.CharField()
passb1 = B()
b1.save()
a1 = A(b=b1)
a1.save()
那么a拿到b的对象
a1.obj_b.name 就能拿到了 a对象绑定的b对象的name字段值
那么b怎么拿到a 呢 使用源模型名(小写)__set方法
b1.a_set.age b就拿到了关联的a对象的age字段值 -
使用related_name属性(覆盖上面的默认方式)
class A(models.Model):
age = models.IntField()
obj_b = models.ForeignKey(B,related_name="obj_a")class B(modes.Model):
name = models.CharField()
passb1 = B()
b1.save()
a1 = A(b=b1)
a1.save()
a拿到b的方式还是一样的
a1.obj_b.name 就能拿到了 a对象绑定的b对象的name字段值
b拿到a 的方式变了,不在是源模型名__set,而是related_name指定的值
b1.obj_a.age b1就拿到了关联的a1对象的age字段值