1、什么是关系映射
在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见的关系映射有:
- 一对一映射
- 如:一个身份证对应一个人
- 一对多映射
- 如:一个班级可以有多个学生
- 多对多映射
class User(models.Model): name = models.CharField(verbose_name=”用户名”, max_length=50) password = models.CharField(verbose_name=”密码”,max_length=32,null=True,blank=True)
class Account(models.Model): user = models.OneToOneField(User,on_delete=models.CASCADE,verbose_name=”用户”)
# 一个平台用户 只有 一个平台账户
money = models.IntegerField(verbose_name="余额",default=90000)
<a name="tixE1"></a>
### 2.1.1、创建时-特殊字段选项
<a name="w68Yw"></a>
#### on_delete 级联删除(删除时说明)
1. models.CASCADE 级联删除。Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象
1. models.PROTECT 抛出ProtectedError 以阻止被引用对象的删除(等同于MySQL默认的RESTRICT)
1. models.SET_NULL 设置ForeignKey null; 需要指定 null=True
1. models.SET_DEFAULT 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。
- on_delete = models.CASCADE #关联删除,删除关联字段后,该字段也同时删除
- on_delete = models.DO_NOTHING #删除后什么也不做
- on_delete =models.SET #设置成指定的值 例如:models.SET(1) 删除关联字段后,本字段设置成1
- on_delete =models.SET_NULL #设置成null
- on_delete =models.SET_DEFAULT #设置成默认值,前提是你这个字段得有默认值
- on_delete =models.PROTECT#受保护 不允许删除
<a name="YQQVL"></a>
## 2.2、创建数据(新增表记录)
模型类
```python
from django.db import models
class User(models.Model):
name = models.CharField(verbose_name="用户名", max_length=50)
password = models.CharField(verbose_name="密码",max_length=32,null=True,blank=True)
class Account(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,verbose_name="用户")
# 一个平台用户 只有 一个平台账户
money = models.IntegerField(verbose_name="余额",default=90000)
- 先创建身上没有定义键关系的表记录
- 再创建身上有定义键关系的表记录
无外键的模型类 User :
创建方式:(先创建身上没有定义键关系的表记)
user1 = User.objects.creat(name=”小新同学”)
有外键的模型类 Account:
(再创建身上有定义键关系的表记录)
创建方式1:
a1 = models.Account.objects.create(money=10000,user=user1) # 关联 小新同学的 object 管理器对象
创建方式2:
a1 = models.Account.objects.create(money=10000,user_id=user1.id) #关联 小新同学对应的主键值
a1 = models.Account.objects.create(money=10000,user_id=1) #关联 小新同学对应的主键值
2.3、查询数据(查询表记录)
正向查询:
直接通过外键属性查询,则称为正向查询
from user import models
a1 = models.Account.objects.get(id=1)
print("账户id是1的用户是",a1.user.name)
反向查询:
没有外键属性的一方,可以调用反向属性查询到关联的另一方
反向关联属性为 实例对象.引用类名(小写),
from user import models
user1 = models.User.objects.get(name="特朗普")
print(user1.name,"的账户余额是:",user1.account.money)
# 直接通过account外键属性查询,则称为正向查询
3、一对多关系映射
一对多是表现现实事物间存在一对多的对应关系
如:一个文章分类有多篇文章,
一对多需要明确出具体角色,在多表上设置外键
3.1、一对多关系创建
语法:
当一个A类对象(文章分类)可以关联多个B类对象(文章)时
ForeignKey必须指定 on_delete模式
related_name参数:自定义一个名称,用于反向查询
当一张子表里,多个foreignkey指向同一个主表,related_name必须设置。
class A(model.Model):
...
class B(model.Model):
属性 = models.ForeignKey("一"的模型类 , on_delete=xxx)
示例:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=50, unique=True, verbose_name="分类名称")
class Article(models.Model):
title = models.CharField(max_length=80, verbose_name="文章名称")
content = models.TextField(verbose_name="文章内容")
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, verbose_name="归属分类")
# ForeignKey定义外键,创建1对多关系
3.2、创建数据
- 先创建“一”
- 再创建“多” ```python from user import models
c1 = models.Category.objects.create(name=”Python文章分类”)
models.Article.objects.create(title=”文章1”,category=c1)
通过关联对象创建
models.Article.objects.create(title=”文章2”,category_id=c1.id) models.Article.objects.create(title=”文章2”,category_id=1)
通过关联对象对应的主键创建
<a name="Hboyf"></a>
## 3.3、查询数据
<a name="qnWCL"></a>
### 正向查询:
通过 category **属性**查询即可
```python
a1 = models.Article.objects.get(title="文章1")
print(a1.title,"的所属文章分类是",a1.category.name)
反向查询:
通过 Category(文章分类) 查询对应的所有 Article(文章)
需要用到反向属性
c1 = models.Category.objects.get(name="Python文章分类")
articles = c1.article_set.all()
# 通过article_set 获取c1 对应的多个 Article数据对象
# articles = models.Article.objects.filter(category=c1)
# 也可以采用这种方式获取
print("Python文章分类,下的文章有:")
for a in articles:
print(a.title)
4、多对多关系映射
定义:
多对多表达对象之间多对多的复杂关系;
如:每个班级都有不同的老师(张老师、李老师、王老师),每个老师都有不同的班级(1班,2班,3班)
MySQL、SQLit 等数据库中创建多对多,需要依赖第三张表来实现
Django中无需手动创建第三张表,Django自动完成
4.1、多对多关系创建
语法:
在关联的两个类中的任意一个类中,增加
属性 = models.ManyToManyField(MyModel)
示例:
一个班级可以有多个老师
一个老师可以有多个班级
from django.db import models
class Grade(models.Model):
name = models.CharField(verbose_name="班级名称", max_length=50)
class Teacher(models.Model):
name = models.CharField(verbose_name="老师名称", max_length=50)
grade = models.ManyToManyField(Grade,verbose_name="班级")
4.2、创建数据
方案1:先创建 班级 grade 再关联 teacher
grade1 = models.Grade.objects.create(name="1班")
grade2 = models.Grade.objects.create(name="2班")
teacher1 = grade1.teacher_set.create(name="张老师")
grade2.teacher_set.add(teacher1)
# 张老师 是1班的老师 也是2班的老师
方案2:先创建 teacher 再关联 grade
teacher2 = models.Teacher.objects.create(name="李老师")
grade3 = teacher2.grade.create(name="2班")
teacher2.grade.add(grade1)
# 李老师 是2班的老师,也是1班的老师
4.3、查询数据
正向查询:
正向查询 有多对多属性的对象 查 另一方
通过 Teacher 查询对应的 所有 Grade
此时多对多属性 等价于 object
teacher2.grade.all() # 获取 teacher2 对应的所有 grade 班级的信息
teacher2.grade.filter(name="1班")
# 获取teacher2 李老师 对应的 名字叫做 1班的 班级信息
反向查询
通过 Grade 查询对应的 所有 Teacher
利用反向属性 teacher_set
grade1.teacher_set.all()
grade1.teacher_set.filter()
多对多小练习
待补充
参考博客
知乎:Django进阶笔记(1)——ForeignKey的爱恨情仇
https://zhuanlan.zhihu.com/p/25393972
CSDN:Django如何创建指向同一个模型的多个外键?
https://blog.csdn.net/laiqun_ai/article/details/45740543