Django文档——Model中的ForeignKey,ManyToManyField与OneToOneField
关联关系字段 (Relationship fields)
ForeignKey,ManyToManyField与OneToOneField分别在Model中定义多对一,多对多,一对一关系。
例如,一本书由一家出版社出版,一家出版社可以出版很多书。一本书由多个作者合写,一个作者可以写很多书。
class Author(models.Model):name=models.CharField(max_length=20)
class Publisher(models.Model):name=models.CharField(max_length=20)
class Book(models.Model):name=models.CharField(max_length=20)pub=models.ForeignKey(Publisher)authors=models.ManyToManyField(Author)
1.关联尚未定义的Model
如果你要与某个尚未定义的 model 建立关联 ,就使用 model 的名称,而不是使用 model 对象本身。
例子中,如果Publisher与Author在Book后面定义,需要写成下面的形式:
class Book(models.Model):name=models.CharField(max_length=20)pub=models.ForeignKey('Publisher')authors=models.ManyToManyField('Author')
2.Model关联自身
Model可以与自身做多对一关系
class People(models.Model):name=models.CharField(max_length=20)leader=models.ForeignKey('self',blank=True,null=True)
Model也可以与自身做多对多关系
class Person(models.Model):friends = models.ManyToManyField("self")
默认情况下,这种关联关系是对称的,如果Person1是Person2的朋友,那么Person2也是Person1的朋友
p1=Person()
p1.save()
p2=Person()
p2.save()
p3=Person()
p3.save()
p1.friends.add(p2,p3)
上述情况下,要查找p3的朋友,不用p3.person_set.all(),而直接用p3.friends.all()就可以了
如果想取消这种对称关系,将symmetrical设为False
class Person2(models.Model):friends=(models.ManyToManyField("self",symmetrical=False)
这样查询p3的朋友,就需要p3.person_set.all()了
3.反向名称related_name
反向名称,用来从被关联字段指向关联字段。
注意,在你定义 抽象 model (abstract models) 时,你必须显式指定反向名称; 只有在你这么做了之后, 某些特别语法 (some special syntax) 才能正常使用。
class Book(models.Model):name=models.CharField(max_length=20)pub=models.ForeignKey(Publisher,related_name='pub')authors=models.ManyToManyField(Author,related_name='author')
这样用Publisher或者Author反向查询Book时可以用related_name了:publisher1.pub.all()或者author1.author.all()。
如果不想设置反向关系,设置related_name为’+‘或者以’+'结束。
user = models.ForeignKey(User, related_name='+')
如果有多个ManyToManyField指向同一个Model,这样反向查询FOO_set的时候就无法弄清是哪个ManyToManyField字段了,可以禁止反向关系:
users = models.ManyToManyField(User, related_name='u+')
referents = models.ManyToManyField(User, related_name='ref+')
4.数据库表现 (Database Representation)
多对一:Django 使用ForeignKey字段名称+ “_id” 做为数据库中的列名称。在上面的例子中,BOOK model 对应的数据表中会有 一个 publisher_id 列。
你可以通过显式地指定 db_column 来改变该字段的列名称,不过,除非你想自定 义 SQL ,否则没必要更改数据库的列名称。
多对多:Django 创建一个中间表来表示ManyToManyField关系。默认情况下,中间表的名称由两个关系表名结合而成。
由于某些数据库对表名的长度有限制,所以中间表的名称会自动限制在64个字符以内,并包含一个不重复的哈希字符串。这
意味着,你可能看到类似 book_authors_9cdf4 这样的表名称。你可以使用 db_table 选项手动指定中间表名称。
但是,如果你想手动指定中间表,你可以用 through 选项来指定model 使用另外某个 model 来管理多对多关系。而这个 model 就是中间表所对应的 model :
class Person(models.Model):name = models.CharField(max_length=128)def __unicode__(self):return self.name
class Group(models.Model):name = models.CharField(max_length=128)members = models.ManyToManyField(Person, through='Membership')def __unicode__(self):return self.name
class Membership(models.Model):person = models.ForeignKey(Person)group = models.ForeignKey(Group)date_joined = models.DateField()invite_reason = models.CharField(max_length=64)
这样,就可以记录某个person何时加入group了。
要建立Person与Group的关系就不能用add,create,remove了,而是需要通过Membership进行。
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()
clear()还是可以使用的beatles.members.clear()
当多对多关系关联自身时,中间表的ForeignKey是可以指向同一个Model的,但是它们必须被看做ManyToManyField的两边,而不是对称的,需要设置 symmetrical=False。
5.其它参数 (Arguments)
5.1 ForeignKey 接受下列这些可选参数,这些参数定义了关系是如何运行的。
ForeignKey.limit_choices_to
它是一个包含筛选条件和对应值的字典,用来在 Django 管理后台筛选 关联对象。例如,利用 Python 的 datetime 模块,过滤掉不符合筛选条件关联对象:
limit_choices_to = {‘pub_date__lte’: datetime.date.today}
只有 pub_date 在当前日期之前的关联对象才允许被选。
也可以使用 Q 对象来代替字典,从而实现更复杂的筛选。当limit_choices_to为Q对象时,如果把此外键字段放在ModelAdmin的raw_id_fields时是不可用的。
ForeignKey.to_field
指定当前关系与被关联对象中的哪个字段关联。默认情况下,to_field 指向被关联对象的主键。
ForeignKey.on_delete
当一个model对象的ForeignKey关联的对象被删除时,默认情况下此对象也会一起被级联删除的。
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
CASCADE:默认值,model对象会和ForeignKey关联对象一起被删除
SET_NULL:将model对象的ForeignKey字段设为null。当然需要将null设为True。
SET_DEFAULT:将model对象的ForeignKey字段设为默认值。
Protect:删除ForeignKey关联对象时会生成一个ProtectedError,这样ForeignKey关联对象就不会被删除了。
SET():将model对象的ForeignKey字段设为传递给SET()的值。
def get_sentinel_user():return User.objects.get_or_create(username='deleted')[0]class MyModel(models.Model):user = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
DO_NOTHING:啥也不做。
5.2 ManyToManyField 接受下列可选参数,这些参数定义了关系是如何运行的。
ManyToManyField.limit_choices_to
和 ForeignKey.limit_choices_to 用法一样。
limit_choices_to 对于通过 through 参数指定了中介表的 ManyToManyField 不起作用。
ManyToManyField.symmetrical
只要定义递归的多对多关系时起作用。
ManyToManyField.through
手动指定中间表
ManyToManyField.db_table
指定数据库中保存多对多关系数据的表名称。如果没有提供该选项,Django 就会根据两个关系表的名称生成一个新的表名,做为中间表的名称。
6.OneToOneField
class OneToOneField(othermodel[, parent_link=False, **options])
用来定义一对一关系。笼统地讲,它与声明了 unique=True 的 ForeignKey 非常相似,不同的是使用反向关联的时候,得到的不是一个对象列表,而是一个单独的对象。
在某个 model 扩展自另一个 model 时,这个字段是非常有用的;例如: 多表继承 (Multi-tableinheritance) 就是通过在子 model 中添加一个指向父 model 的一对一关联而实现的。
必须给该字段一个参数:被关联的 model 类。工作方式和 ForeignKey 一样,连递归关联 (recursive) 和 延后关联 (lazy) 都一样。
此外,OneToOneField 接受 ForeignKey 可接受的参数,只有一个参数是 OnetoOneField 专有的:OneToOneField.parent_link
如果为 True ,并且作用于继承自某个父 model 的子 model 上(这里不能是延后继承,父 model 必须真实存在 ),那么该字段就会变成指向父类实例的引用(或者叫链接),
而不是象其他OneToOneField 那样用于扩展父类并继承父类属性。
from django.db import models, transaction, IntegrityErrorclass Place(models.Model):name = models.CharField(max_length=50)address = models.CharField(max_length=80)def __unicode__(self):return u"%s the place" % self.nameclass Restaurant(models.Model):place = models.OneToOneField(Place, primary_key=True)serves_hot_dogs = models.BooleanField()serves_pizza = models.BooleanField()def __unicode__(self):return u"%s the restaurant" % self.place.nameclass Waiter(models.Model):restaurant = models.ForeignKey(Restaurant)name = models.CharField(max_length=50)def __unicode__(self):return u"%s the waiter at %s" % (self.name, self.restaurant)
使用反向关联的时候,得到的不是一个对象列表,而是一个单独的对象:
p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
p1.save()
r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)r.save()p1.restaurant
<Restaurant: Demon Dogs the restaurant>Place.objects.get(restaurant__place__name__startswith="Demon")
<Place: Demon Dogs the place>Waiter.objects.filter(restaurant__place__name__startswith="Demon")
Django文档——Model中的ForeignKey,ManyToManyField与OneToOneField相关推荐
- django文档: Model中的ForeignKey, ManyToManyField, OneToOneField
Django文档--Model中的ForeignKey,ManyToManyField与OneToOneField 关联关系字段 (Relationship fields) ForeignKey,Ma ...
- Django-Model中的ForeignKey,ManyToManyField与OneToOneField
关联关系字段 (Relationship fields) ForeignKey,ManyToManyField与OneToOneField分别在Model中定义多对一,多对多,一对一关系. 例如,一本 ...
- django文档_如何在django官方文档中快速找到需要的内容
许多新手程序员发现Django文档内容非常庞大. 假设想学习如何为用户执行登录.看着很简单:登录是Django的核心功能.如果搜索" django登录"或搜索文档,则会看到一些选项 ...
- Django 文档 -- 记录我的Django学习之旅
我的学习之旅 执行查询:https://docs.djangoproject.com/zh-hans/3.1/topics/db/queries/ 执行原生 SQL 查询:https://docs.d ...
- 读django文档——Managing static files (e.g. images, JavaScript, CSS)
在上一篇读django文档--nginx + uwsgi 部署django项目_苦行僧的妖孽日常-CSDN博客 部署django项目后,发现在runserver时都能正常部署的 static 文件都 ...
- 服务器根目录文件配置文件,在文档根目录中存储安装和配置文件
在文档根目录中存储安装和配置文件 wanboot-cgi 程序在 WAN Boot 安装过程中传输以下文件. wanboot 程序 WAN Boot 最小根文件系统 定制 JumpStart 文件 S ...
- MFC使用OpenCV在文档窗口中显示图像(支持多图片格式)
MFC使用OpenCV在文档窗口中显示图像 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/72550659 在VS ...
- 可视化webpart基础开发——TreeView控件读取文档库中的所有文件夹和文件(递归方法读取) ....
可视化webpart基础开发--TreeView控件读取文档库中的所有文件夹和文件(递归方法读取) 作者:miragesky2049 原文地址:http://blog.csdn.net/mirages ...
- VBA读取html表格内容,科学网—VBA读取word文档表格中table的cell的text文本 - 付安民的博文...
VBA读取word文档表格中table的cell的text文本 已有 11546 次阅读 2010-6-4 16:40 |个人分类:学习篇|系统分类:科研笔记 Sub Readtable() Dim ...
最新文章
- Excel实战技巧之[活用条件格式]
- Set Up a Mobile Worker
- 计算机硬件基础大纲,计算机硬件技术基础大纲_.doc
- 已知圆心 坐标和一点坐标和角度 就之后的坐标_《6. AutoCAD 标注角度尺寸》
- 如何免费申请用于开发目的的Hybris Commerce license
- 病毒的手工排除与分析(更新完毕)
- 设计模式之十五:訪问者模式(Visitor Pattern)
- 数据库建模工具powerdisgner16.5
- Visual studio 番茄助手过期解决方案
- MATLAB人脸识别
- PCB Layout 注意事项——布线
- linux 卸载skype,在Ubuntu 20.04系统下使用snap和apt安装Skype的方法
- php 字典树,关于PHP字典树的定义与实现方法
- python乒乓球比赛规则介绍_乒乓球比赛规则简介
- 论文:YOLOX: Exceeding YOLO Series in 2021
- Flutter笔记--Sliver用法
- 论文整理Perception-aware Receding Horizon Navigation for MAVs
- 深恶痛绝的No mapping found for HTTP request with URI
- matlab 填补空洞,OpenCV空洞填充算法
- 终生学习者,永远劳苦命!