文章目录
番外篇:外键那些事儿
1、什么是外键
外键是数据表用来指向某个外来的键值的字段。这个外键键值代表另外一个表的某条记录
2、为什么使用外键(作用)
- 1、去除冗余的数据
- 2、数据结构化,使用和执行效率更高
- 3、便于管理,更好地存储数据
3、外键的种类
- 常见外键:ForeignKey
- 多对多:ManyToManyField
- 一对一:OneToOneField
- 万能外键:ContentType
github外键示例代码
4、ForeignKey
- 1、原理
- 2、如何使用
- 举例:学生与班级
- 3、属性说明
- 第1个参数
- on_delete
- default
- 4、正向和反向
- 正向:顺理成章
- 反向:冥冥之中
- 5、编辑
示例:models.py:
from django.db import models
# Create your models here.
# https://docs.djangoproject.com/en/2.2/ref/models/fields/#module-django.db.models.fields.related
# 班级表
class SchoolClass(models.Model):
class_name = models.CharField(max_length=12)
class_master = models.CharField(max_length=12)
def __str__(self):
return '<SchoolClass: {0}>'.format(self.class_name)
__unicode__ = __str__
# 学生表
class Student(models.Model):
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE)
# (on_delete属性说明)
# 必填,对应关联的记录(班级),删除的时候,该记录(学生)怎么处理
# 参考:https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ForeignKey.on_delete
# 1、CASCADE, 级联删除。
# 当班级删除记录的时候,删除对应的所有学生。确保数据完整
# 2、PROTECT, 保护。
# 当班级删除记录的时候,若有学生关联该班级,则不给删除班级
# 3、SET_NULL, 设置为NULL。
# 当班级删除记录的时候,若有学生关联该班级,则将这些学生的班级外键字段,值设置为null。
# school_class = models.ForeignKey(SchoolClass, on_delete=models.SET_NULL, null=True) # 需要设置null为True
# 4、SET_DEFAULT,设置为默认值。
# def default_class():
# return SchoolClass.objects.first()
# school_class = models.ForeignKey(SchoolClass, on_delete=models.SET_DEFAULT, default=default_class) # 需要设置default
# 5、SET(),自定义方法,返回一个值,设置该字段的值
# 参考:https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.SET
# 6、DO_NOTHING,什么时候都不做。
# 这个会破坏数据完整性,慎用。
# (正向:顺理成章)
# s = Student.objects.first()
# s.school_class # 找到关联的班级对象
# (反向:冥冥之中)
# c = SchoolClass.objects.first()
# c.student_set.all() # xxxx_set 找到被关联的对象
# related_name,明确关系,班级通过什么属性找到学生
# school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE, related_name='students')
# c = SchoolClass.objects.first()
# c.students.all()
# 编辑该字段,直接赋值即可
# c = SchoolClass.objects.first()
# s = Student()
# s.student_name = 'test'
# s.school_class = c
# s.save()
SEX_CHOICES = (
(0, '男'),
(1, '女'),
)
student_name = models.CharField(max_length=12)
sex = models.IntegerField(choices=SEX_CHOICES, default=0)
def __str__(self):
return '<Student: {0}>'.format(self.student_name)
__unicode__ = __str__
5、ManyToManyField
- 1、原理
- 2、如何使用
- 举例:书籍和作者
- 3、属性说明
- 第1个参数
- on_delete
- 4、正向和反向
- 5、编辑
示例 models.py:
from django.db import models
# Create your models here.
# 作者表
class Author(models.Model):
author_name = models.CharField(max_length=24)
def __str__(self):
return '<Author: {0}>'.format(self.author_name)
__unicode__ = __str__
# 书籍表
class Book(models.Model):
book_name = models.CharField(max_length=48)
authors = models.ManyToManyField(Author)
def __str__(self):
return '<Book: {0}>'.format(self.book_name)
__unicode__ = __str__
# 正向(顺理成章)
# book = Book.objects.first()
# authors = book.authors.all() # 获得该书所有作者
# 反向(冥冥之中)
# author = Author.objects.first()
# books = author.book_set.all() # 获得该作者所有书
# related_name,明确关系,同ForeignKey
# authors = models.ManyToManyField(Author, related_name='books')
# 编辑ManyToMany字段,无需执行save()保存
# 参考:https://docs.djangoproject.com/en/2.2/ref/models/relations/#django.db.models.fields.related.RelatedManager
# add, remove, clear
# book = Book.objects.first()
# author = Author.objects.first()
# 1、书籍新增作者
# book.authors.add(author)
# 2、书籍移除作者
# book.authors.remove(author)
# 3、作者添加书籍
# author.book_set.add(book)
# 4、作者移除书籍
# author.book_set.remove(book)
6、OneToOneField
- 1、原理
- 2、如何使用
- 举例:Django用户表和自定义用户拓展表
- 3、属性说明
- 第1个参数
- on_delete
- 4、正向和反向
- 5、编辑
示例models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
nickname = models.CharField(max_length=24)
def __str__(self):
return '<Profile: {0}>'.format(self.nickname)
__unicode__ = __str__
# 基本使用方法和ForeignKey一样
# 正向:顺理成章
# profile = Profile.objects.first()
# user = profile.user
# 反向:冥冥之中,我知道你的存在
# user = User.objects.first()
# profile = user.profile
# 编辑该字段,直接赋值即可
7、ContentType
- 1、原理
- 2、如何使用
- 举例:评论任何对象
- 3、字段说明
- 4、正向和反向
- GenericRelation
- 5、编辑
示例 models.py:
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
# Create your models here.
# 文章表
class Article(models.Model):
title = models.CharField(max_length=36)
content = models.TextField(blank=True)
# comments = GenericRelation('Comment') # 由于Comment后面才定义,所以用字符串惰性引用
def __str__(self):
return '<Article: {0}>'.format(self.title)
__unicode__ = __str__
# 视频表
class Video(models.Model):
video_name = models.CharField(max_length=36)
url = models.URLField()
def __str__(self):
return '<Video: {0}>'.format(self.video_name)
__unicode__ = __str__
# 评论表
class Comment(models.Model):
# 无法同时指向多个对象
# article = models.ForeignKey(Article, on_delete=models.CASCADE)
# video = models.ForeignKey(Video, on_delete=models.CASCADE)
# 万能关系
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) # 记录关联对象的类型
object_id = models.PositiveIntegerField() # 记录关联对象的主键值
content_object = GenericForeignKey('content_type', 'object_id') # 常规字段,便于使用
# 评论内容
text = models.TextField()
def __str__(self):
return '<Comment: {0}>'.format(self.text)
__unicode__ = __str__
# 正向,使用content_object可直接访问
'''
comment = Comment.objects.first()
obj = comment.content_object # 直接得到所被评论的对象
'''
# 反向,无法直接从其他对象找到Comment对应的评论
'''
from django.contrib.contenttypes.models import ContentType
article = Article.objects.first()
article_content_type = ContentType.objects.get_for_model(article)
# 通过Comment自身的筛选查询得到
comments = Comment.objects.filter(content_type=article_content_type, object_id=article.pk)
'''
# 反向,方法2,主动建立关系
# 参考:https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#reverse-generic-relations
'''
from django.contrib.contenttypes.fields import GenericRelation
# 对应模型加入 comments = GenericRelation('Comment') 字段
article = Article.objects.first()
comments = article.comments.all()
'''
# content type 官方文档
# https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/
# 更多可以参考,我的Django2.0教程,第22课 评论功能设计和用户登录
# 链接:https://www.bilibili.com/video/av21029850
8、修改外键注意事项
- 修改外键容易出错,尤其是一个外键改成另外一种外键类型
- 建议:分多次操作
- 例如:先删除,执行数据库迁移操作,再新建字段,再执行数据库迁移操作