Many-to-one relationships
一对一关系,一对一关系应该使用来分离抽象模型的,不让一张表里面的字段那么多,那么乱。
models.py
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant)
name = models.CharField(max_length=50)
def __str__(self): # __unicode__ on Python 2
return "%s the waiter at %s" % (self.name, self.restaurant)
Restaurant
表中的 place
字段是 和 Place
表是一对一的关系,且手动设置成了主键,一家餐厅有一个地址,这样把模型都分开来,虽然查询的时候可能比较麻烦,但这样分开来能更好的抽象模型的关系,我的应用里面也能够这么做,一个表中的字段太多,有的能够分离到一对一的关系中,也更好理解些。
python manage.py shell
API 用法
实例化 Place
对象
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
实例化 Restaurant
对象,将前面实例化好的的 Place
对象绑定上去
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
通过 Restaurant
获取其地点
>>> r.place
<Place: Demon Dogs the place>
通过 Place
获取其绑定的 Restaurant
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurane>
p2
没有绑定任何 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
重新绑定 Place
对象到 Restaurant
中
>>> r.place = p2
>>> e.save()
>>> p2.restaurant
<Restaurant: Ace Hardware the restaurant>
>>> r.place
<Place: Ace Hardware the place>
r
的地点原来是 p1
,重新绑定成 p2
,验证已经变成了 p2
的地址。
重新设置回来:
>>> p1.restaurant = r
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
不能绑定一个没有保存到数据库中的对象到另一个对象中,否则会触发 ValueError
>>> p3 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> Restaurant(place=p3, serves_hot_dogs=True, serves_pizza=False)
Traceback (most recent call last):
...
ValueError: 'Cannot assign "<Place: Demon Dogs>": "Place" instance isn't saved in the database.'
>>> p.restaurant = Restaurant(place=p, serves_hot_dogs=True, serves_pizza=False)
Traceback (most recent call last):
...
ValueError: 'Cannot assign "<Restaurant: Demon Dogs the restaurant>": "Restaurant" instance isn't saved in the database.'
这上面的错误其实有两个,第一是 p3
实例化没有保存,然后就是 第二行完全没来由,没有实例化任何 Restaurant
对象就要把 p3
绑定上去,触发两个 ValueError
异常。
Django 1.8 的改变: 前面也好几处提过了,绑定未保存的对象将会静默数据丢失,不会引发任何异常。
其他用法就是增删改差了
>>> Restaurant.objects.all()
[<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>]
>>> Place.objects.order_by('name')
[<Place: Ace Hardware the place>, <Place: Demon Dogs the place>]
>>> Restaurant.objects.get(place=p1)
>>> Restaurant.objects.get(place__pk=1)
>>> Restaurant.objects.filter(place__name__startswith="Demon")
>>> Restaurant.objects.exclude(place__address__contains="Ashland")
>>> w = r.waiter_set.create(name='Joe')
>>> w.save()
>>> w
<Waiter: Joe the waiter at Demon Dogs the restaurant>
>>> Waiter.objects.filter(restaurant__place=p1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant__place__name__startswith="Demon")
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]