【Django2.0学习笔记】番外篇:外键那些事儿

番外篇:外键那些事儿

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、修改外键注意事项

  • 修改外键容易出错,尤其是一个外键改成另外一种外键类型
  • 建议:分多次操作
  • 例如:先删除,执行数据库迁移操作,再新建字段,再执行数据库迁移操作
    在这里插入图片描述
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值