Django-ORM之ForeignKey的使用-多对一关系
ForeignKey使用俩表示两张表多对一关系的外键,外键字段要定义在多属性的表中。
定义外键时,to的表可以直接写类名,但是需要注意类的定义顺序;也可以写字符串式的类名,这样就可以忽略class类的定义顺序;
class Book(models.Model): title = models.CharField(max_length=32) pid = models.ForeignKey('Publisher',on_delete=models.CASCADE) # 外键 on_delete属性 2.0 必填 ,1.0版本默认是models.CASCADE,建议是手动写上
【实例】
class Book(models.Model): bid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) pub = models.ForeignKey("Publisher", on_delete=models.CASCADE) def __str__(self): return f"{self.bid}{self.title}{self.pub}"
创建完成后会发生如图这种情况,pub自动变成了pub_id,无需惊讶,这就是它应有的样子~
那么pub与pub_id之间有什么关系呢?听经过查看pub的type可以得出结论,pub得到的是一个对象,包含pub_id在内的外键对应的对象,在django中创建外键时,默认是以目标的主键作为对应项,以下的各个操作就会利用这一点。
在本例中外键中 pub_id == pub.pid
查询
all_books = models.Book.objects.all() print(all_books) for book in all_books: print(book) print(book.pk) print(book.title) print(book.pub,type(book.pub)) # 所关联的对象 print(book.pub_id,type(book.pub_id)) # 所关联的对象的pk print('*' * 32)
新增
# 方式一 models.Book.objects.create(title=title,pub=models.Publisher.objects.get(pk=pub_id)) # 方式二 models.Book.objects.create(title=title, pub_id=pub_id)
删除
pk = request.GET.get('pk') models.Book.objects.filter(pk=pk).delete()
编辑
book_obj.title = title # 修改外键列 # 方式一: book_obj.pub_id = pub_id # 方式二: book_obj.pub = models.Publisher.objects.get(pk=pub_id) book_obj.save()
外键的操作
【新建测试表结构】
from django.db import models # Create your models here. class Publisher(models.Model): name = models.CharField(max_length=32) city = models.CharField(max_length=32) def __str__(self): return "<Publisher object: {} {}>".format(self.id, self.name) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() phone = models.CharField(max_length=11) def __str__(self): return "<Author object: {} {}>".format(self.id, self.name) class Book(models.Model): title = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) price = models.DecimalField(max_digits=5, decimal_places=2) memo = models.TextField(null=True) # 创建外键,关联publish publisher = models.ForeignKey(to="Publisher",null=True, on_delete=models.CASCADE) # 创建多对多关联author author = models.ManyToManyField(to="Author") def __str__(self): return "<Book object: {} {} {} {}>".format(self.id, self.title,self.price,self.author)
跨表对象查找正向
所谓正向查找是指从建立外键的表查询目标表的查找,兄目标表查询建立外键的表就是反向查询。
book_obj = models.Book.objects.first() print(book_obj) # 输出book对象 print(book_obj.publisher) # book对象对应的外键对象 print(book_obj.publisher.name) # 外键对象的name属性
跨表对象查找反向
pub_obj = models.Publisher.objects.get(pk=1) print(pub_obj) # 出版社对象 print(pub_obj.name) # 出版社名称 print(pub_obj.book_set) # 关系管理对象,与该出版社相关联的图书的关系,默认的书写方式:类名小写_set print(pub_obj.book_set.all()) # 所关联的所有的对象
添加relate_name属性
定义反向查询时的名字,例如将Book表的publisher属性添加related_name属性,会抵消默认情况的类名小写_set
:
# 添加属性 publisher = models.ForeignKey(to="Publisher",null=True, on_delete=models.CASCADE,related_name='books') # 未添加属性时,反向查询 pub_obj = models.Publisher.objects.get(pk=1) print(pub_obj.book_set) print(pub_obj.book_set.all()) # 添加属性后的反向查询 pub_obj = models.Publisher.objects.get(pk=1) print(pub_obj.books) print(pub_obj.books.all())
跨表字段查找正向
# 查询'叽叽喳喳出版社'出版的书 ret = models.Book.objects.filter(publisher__name='叽叽喳喳出版社') print(ret.all())
跨表字段查找反向
# 查找出版《叽叽喳喳》的出版社 ret = models.Publisher.objects.filter(book__title='叽叽喳喳') print(ret.values())
添加related_name属性
# 添加属性 publisher = models.ForeignKey(to="Publisher",null=True, on_delete=models.CASCADE,related_name='books') # 反向查询时 ret = models.Publisher.objects.filter(books__title='叽叽喳喳') print(ret)
添加related_query_name属性
在字段查找时related_query_name的优先级高于related_name,但是在对象查找时,related_query_name无效
publisher = models.ForeignKey(to="Publisher",null=True, on_delete=models.CASCADE,related_name='books',related_query_name='books1') # 反向查询时 ret = models.Publisher.objects.filter(books1__title='叽叽喳喳') print(ret)
关系管理对象的方法
反向查询时才能取到关系管理对象 # all pub_obj = models.Publisher.objects.get(pk=1) print(pub_obj.book_set.all()) # set 设置对象 pub_obj.book_set.set(models.Book.objects.filter(pk__in=[3,4])) # add 添加对象 pub_obj.book_set.add(*models.Book.objects.filter(pk__in=[1,2])) # remove 移除外键,前提是外键字段可以为空 pub_obj.book_set.remove(*models.Book.objects.filter(pk__in=[1,2])) # clear 清空,前提是外键字段可以为空 pub_obj.book_set.clear(*models.Book.objects.filter(pk__in=[1,2])) # create pub_obj.book_set.createtitle='叽叽喳喳的世界',publisher_id=2,price=99.9)
仅供参考,欢迎指正