什么是外键?
外键是数据表用来指向某个外来的键值的字段。
为什么使用外键?
1.取出冗余数据
2.数据结构化,使用和执行效率变高
3.便于管理,更好存储数据。
外键的种类
常见外键:ForeignKey
多对多:ManyToManyField
一对一:OneToOneField
万能外键:ContentType
ForeignKey
```python
from django.dbimport models
#coding=utf-8
# Create your models here.
class StudentClass(models.Model):
name= models.CharField(max_length=12,help_text='班级名称')
master= models.CharField(max_length=12,help_text='班主任')
def __str__(self):
return 'StudentClass:' + self.name
class Student(models.Model):
name= models.CharField(max_length=12,help_text='学生姓名')
school_class= models.ForeignKey(StudentClass,on_delete=models.CASCADE)
#(on_delete 属性说明)
#django 1.9一定需要的
#1.CASCADE,级联删除
#当班级记录删除时,删除对应的所有学会
#2.DO_NOTHING 什么都不做
#会破坏数据的完整性
#3.PROTECT 保护
#当班级删除记录的时候,若有学生关联班级,则不给删除班级
#4.SET_NULL,设置为NULL
#当班级删除记录的时候,若有学生关联该班级,则这些学生的班级关联字段全都设置为NULL
# school_class = models.ForeignKey(StudentClass,on_delete=models.SET_NULL, null=True)
#5.SET_DEFAULT 设置为默认值
# def default_class():
# return SchoolClass.objects.first()
# school_class = models.ForeignKey(StudentClass, on_delete=models.SET_DEFAULT, default=default_class)
#6.SET() 自定义方法,返回一个值,设置该字段的值
"""
外键查询数据 1.正向查询s = student.objects.first()
s.school_class #找到关联的班级对象"""
"""
2.反向查询c = StudentCLass.objects.first()
c.student_set.all()
related_name, 明确关系,班级通过什么属性找到学生school_class = models.ForeignKey(StudentClass, on_delete=moels.CASCADE, related_name='student')
c = StudentClass.objects.first()
c.student.all()
"""
```
MangToManyField
如:一本书可能有多个作者,一个作者可能出了多本书
```
#coding=utf-8
from django.dbimport models
# Create your models here.
class Author(models.Model):
author_name= models.CharField(max_length=50)
def __str__(self):
return 'author_name:'+ self.author_name
class Book(models.Model):
book_name= models.CharField(max_length=50)
authors= models.ManyToManyField(Author,through='BookAuthor')
class BookAuthor(models.Model):
author= models.ForeignKey(Author,on_delete=models.CASCADE)
book= models.ForeignKey(Book,on_delete=models.CASCADE)
#还可以添加额外字段
#dir()找到它有那些属性
#多对多字段会创建一个维护多对多关系的表 默认book_author表
#可以使用through 指向中间表,自己来创建这个中间表
"""
正向查询book = Book.objects.first()
authors = book.author.all()
反向查询author = Author.objects.first()
books = author.book_set.all() #如果指定了relate_name 那么就要换名称了related_name,明确关系,同ForeignKey
authors = models.ManyToManyField(Author, related_name = 'books')
编辑ManyToMany 字段,无需执行save()保存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.boos_set.remove(book)
"""
```
OneToOneField
如:Django用户表和自定义用户拓展表
```
on_delete
class Profile(models.Model):
user = models.OneToOneField(User,on_delete = models.CASCADE)
nickname = models.CharField(max_length=24)
'''
正向
profile = Profile.objects.first()
user = profile.user
反向
user = User.objects.first()
profile = user.profile
编辑该字段直接赋值就可以
'''
```
ContentType
如:评论任何对象,评论表不仅能指向文章,还可以指向视频
1.评论表中有两个字段维护这个关系
一个记录类型
一个记录值
class Viedo(models.Model): ...
class Article(models.Model): ...
class Comment(models.Model):
content_type = models.ForeignKey(ContentType, on_delete = CASCADE) #记录关联对象的类型
object_id = models.PositiveIntegerField() #记录关联对象的主键值
content_objects = GenericForeignKey('content_type' , 'object_id)#常规字段,便于使用
text=...#评论内容
'''
正向:
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 =rticle_content_type, object_id = article.pk)
反向方法2:主动建立关系
from django.contrib.contenttypes.fields import GenericRelation
#对应模型加入 comments = GenericRelation(‘Comment')字段
article = Article.objects.first()
comments = article.comments.all()
'''