根据Django官方文档介绍:
A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object.
OneToOneField与ForeignKey加上unique=True效果基本一样,但是用OneToOneField反向关联会直接返回对象。
相反地,使用ForeignKey, 反向关联后会返回QuerySet。
例子:
from django.db import models
class Engine(models.Model):
name = models.CharField(max_length=25)
def __unicode__(self):
return self.name
class Car(models.Model):
name = models.CharField(max_length=25)
engine = models.OneToOneField(Engine)
def __unicode__(self):
return self.name
class Engine2(models.Model):
name = models.CharField(max_length=25)
def __unicode__(self):
return self.name
class Car2(models.Model):
name = models.CharField(max_length=25)
engine = models.ForeignKey(Engine2, unique=True)
def __unicode__(self):
return self.name
在python manage.py shell里输入:
>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car # OneToOneField的反向关联属性如果没有写relate_name, 则是对方类名的小写
<Car: Audi>
>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all() # OneToOneField的反向关联属性如果没有写relate_name, 则是对方类名的小写_set
[<Car2: Mazda>]
补充知识:Django ForeignKey,ManyToManyField和OneToOneField的辨析
导引
模型(Models)是对网站所需信息种类的定义,其包含了网站存储数据中的重要字段和数据行为。一般来说,一个模型对于数据库中的一个表单。
字段(Fields)是模型的重要和唯一组成部分,他们由类别的属性值所指定。
Field分类
由官方文档Model field reference | Django Documentation定义:
Field一共分为AutoField、BinaryField、BooleanField、CharField、DateField、DecimalField、EmailField、FileField、FloatField、IntegerField、TextField、TimeField、URLField等类别,丰富的类别选项为数据库存储方式提供了完善的支持,而本文主要是针对如下三个关系型字段(Relationship fields):
关系型字段 | 对应关系 |
---|---|
ForeignKey | 多对一 |
ManyToManyField | 多对多 |
OneToOneField | 一对一 |
分析
ForeignKey
首先查看源码,在类的开头有如下参数:
many_to_many = False
many_to_one = True
one_to_many = False
one_to_one = False
由此可见,ForeignKey是many_to_one类型的,即“一对多”,我们引用官方文档给出的示例:
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
由此我们可以看到,Car类型中有manufacturer字段,其类型是对应Manufacturer类的ForeignKey。我们可以根据生活常识理解这种定义,由于一部汽车对应一个生产商,而一个生产商可以对应许多部汽车,所以两者具有“一对多”的关系,在此种情况我们使用ForeignKey。
对于每个ForeignKey,我们需要给出关联的模型和on_delete响应的选项,即
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
on_delete函数的作用是在此字段被删除的时候做出的响应,其可选项如下:
选项 | 功能 |
---|---|
CASCADE | 级联删除,此类选项模仿SQL语句ON DELETE CASCADE,再删除此字段信息的时候同时删除包含ForeignKey字段的目标(object) |
PROTECT | 通过django.db.IntegrityError中的ProtectedError来保护此字段不被删除,若进行删除操作则抛出错误 |
SET_NULL | 将ForeignKey置为空,这只在null选项为True的时候产生作用 |
SET_DEFAULT | 设为默认值(default value),此默认值已预先对ForeignKey设置 |
SET() | 对ForeignKey设置对SET()函数传递的数值 |
DO_NOTHING | 不进行任何操作。若数据库提高了引用完整性,则此种设置会抛出一个IntegrityError,除非对这一数据字段手动添加了SQL语句中的ON DELETE字段 |
还可以通过设置abstract属性来定义一个抽象类:
from django.db import models
class AbstractCar(models.Model):
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
class Meta:
abstract = True
ForeignKey还有如下的参数可以选择:
参数 | 功能 |
---|---|
limit_choices_to | 通过一个限制对字段信息的某一可能选项进行约束,可以通过字典,函数或者查询值来设置 |
related_name | 可以指定关联的类在本类中的名称,通过这一参数可以用两个字段名引用同一个类,通过这个名称父类可以取得子类的值,默认为字段名 |
related_query_name | 用于filter函数过滤和values函数 |
to_field | 关系关联的相关对象名称 |
db_constraint | 控制在数据库中是否应该建立这一字段的约束 |
swappable | 用于控制这一字段对于可交换类模型的行为 |
ManyToManyField
同样在源码中我们可以找到针对ManyToManyField的如下定义:
many_to_many = True
many_to_one = False
one_to_many = False
one_to_one = False
由此可以知道,ManyToManyField是针对“many-to-many”即多对多关系定义的,它需要知道它关联的类别。
官方文档给出的示例代码可以帮助理解:
from django.db import models
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
在示例代码中,Pizza类的toppings字段由ManyToManyField与Toppings关联,我们可以由生活常识得出一片披萨上面会有很多种类的佐料,而一种佐料又可以用来制作多种披萨,两者满足“多对多”的关系。
ManyToManyField类有两个经常使用的参数:through和through_fields,通过这两个参数可以十分方便地建立中间项的关联,如示例代码所示:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through='Membership',
through_fields=('group', 'person'),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
在Group类中有ManyToManyField类的字段members,这一字段通过through参数与membership联系起来,后者表示“成员资格”,即表示“团体”与“个人”之间关系的中间项,而“through_fields”字段即为中间项连接起来的两个类名,此处即group和person两个类。
ManyToManyField还有以下参数可以选择:
参数 | 功能 |
---|---|
related_name | 同ForeignKey,可以指定关联的类在本类中的名称 |
related_query_name | 同ForeignKey,应用于filter和values函数 |
limit_choices_to | 同ForeignKey,但如果自己定义了如“Membership”之类的中间类,则不会起到作用 |
symmetrical | 对于迭代定义的ManyToManyField,其为这一字段建立一个单独的属性,而是设定symmetrical属性为True,若期望使用此类迭代关系,可以手动设置其为False |
through | 如上所示,用于设置中间项的名字,可以自己定义一个中间项,若不定义的话系统也会分配一个中间项 |
through_fields | 通过元组来给出中间项关联的两个类名,可以查看上面的示例 |
db_table | 可以通过这一属性来手动设定保存这一字段的数据表名称,若不设置则默认为字段的名称 |
db_contraint | 是否在数据库中建立约束 |
swappable | 设置是否指向一个可交换的模型 |
OneToOneField
源码中对OneToOneField的设置如下:
many_to_many = False
many_to_one = False
one_to_many = False
one_to_one = True
可知其是针对单对单的关系设定的字段。在概念上我们可以理解其为设置unique属性为True的一种类型,区别之处在于它“反向”的数值会返回一个目标值,这对于继承关系的表达十分有用,例如一下示例程序:
from django.conf import settings
from django.db import models
class MySpecialUser(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
supervisor = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='supervisor_of',
)
OneToOneField既包含ForeignKey中的参数,又包含一个额外的参数parent_link,若定义了一个类,其继承了一个非抽象的类,而设置parent_link这个函数为True,则会将这个类视作继承的类的父类,而不是一个新的OneToOneField。
来源:https://blog.csdn.net/GrandG7/article/details/79040244
![](https://www.aspxhome.com/images/zang.png)
![](https://www.aspxhome.com/images/jiucuo.png)
猜你喜欢
- 原文:http://www.smashingmagazine.com/ ... emarkable-favicons/翻译:Blank(怿飞
- 在Python个人博客程序开发实例框架设计中,我们已经完成了 数据库设计、数据准备、模板架构、表单设计、视图函数设计、电子邮件支持 等总体设
- 之前有看过一个博文写的是白社会的设计很好但运营却有些遭,因为对每一个WebGame的推出时间把握不准,会有几个应用同时上线造成影响力的冲突,
- window.onload=function(){ pd(11);} function pd(number) { if(number>
- 举个例子来说,要查找出2007-10-12至2007-10-31之间在网站上注册的会员,选择好日期后,点击“查询”按钮,发现2007-10-
- PDO::errorInfoPDO::errorCode — 返回最后一次操作数据库的错误信息(PHP 5 >= 5.1.0, PEC
- 环境python版本号系统游览器python 3.7.2win7google chrome关于本文本文将会通过爬虫的方式实现简单的百度翻译。
- 背景最近在写一个echarts数据看板,要在一个页面中展示多张图表,所以留给每张图表的尺寸就很小。这也就使得图表x轴的刻度文字全部挤到一起了
- 看了不少朋友的个人网站,有一个小问题,似乎很多朋友都忽略了,那就是版权声明的写法。虽然那只是一小行字,不过作为设计师也好,作为个人的爱好也好
- HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP协议的详细内容
- 今天闲逛在网上时,看到一个11px大小的字体,显示却很清晰,赶紧查看站点的CSS,这字体称叫做:PMingLiu。效果相当不错,相比于我们使
- 在新建数据库或附加数据库后,想添加关系表,结果出现下面的错误: 此数据库没有有效所有者,因此无法安装数据库关系图支持对象。若要继续,请首先使
- Microsoft SQL Server 2000复制的概念:在数据库之间对数据和数据库对象进行复制和分发并进行同步以确保其一致性的一组技术
- 先给一个例子:假设在一个表单中有一个按钮id="save"$(document).ready(function(){&n
- 本文实例讲述了CentOS环境下安装Redis3.0及phpredis扩展测试。分享给大家供大家参考,具体如下:线上的统一聊天及推送系统re
- 最近有网友在留言板里问到jRaiser和jQuery的冲突问题,特此写一篇文章进行解释。冲突的根源众所周知,jQuery是通过一个全局变量$
- 本教程配置好后一劳永逸,不用再配置,每次只需要选择 Python 解释器即可打开KBEngine的服务器项目文件夹(资产目录)其主要工程目录
- 开发环境:Ubuntu16.04+Django 1.11.9+Python2.7一:使用自定义函数输出日志到log文件:import tim
- 做网站数据库,是选SQL Server还是Access好,可能您会说:选MySQL好,不过现在只是讨论IIS+ASP这种架构下的选择,不讨论
- 通常我们做统计图的时候需要借助组件来完成例如mschart,aspchart等但是这个类不需要任何组件,而且使用方便,本站测试可用:clsG