django-外键和表关系

首先说明下ForeignKey的选项

1.edit_inline:

如果不设为 False 的话,它对应的对象就可以在页面上内联编辑,就是说这个对象有自 己独立的
管理界面。如果设为 models.TABULAR 或者 models.STACKED 的话,这个内 联编辑对象分别显
示成一个表格或者一些字段的集合。

2.limit_choices_to:

可以限定对象的值的范围的一个参数和值的字典。结合Python的 datetime 模块的

函数可以根据日期来限定对象。例如,下面的代码:
limit_choices_to = {'pub_date__lte': datetime.now}
把可选对象限定到 pub_date 早于当前时间的对象中。
除字典外,这里也可以是一个可以执行更复杂的查询的 Q 对象
这个选项和 edit_inline 是不兼容的。

3.max_num_in_admin

于内联编辑对象,这个是要在管理界面里显示的相关对象的最多个数。所以,如果披萨最多 只会
有10种配料, max_num_in_admin=10 会保证用户最多输入10种配料。
记住,本项并不保证不会创建10种以上的配料,他只是控制管理界面,而不是在Python的API 层和
数据库层做什么限制。

4.min_num_in_admin

在管理界面中要显示的相关的对象的最少个数。通常,在创建的时候,显示的内联对象的个数 为
num_in_admin 个,在编辑的时候,在当前的基础上又会多显示 num_extra_on_change 个空对
象,但是显示的对象个数不会少于 min_num_in_admin 个。

5.num_extra_on_change

修改对象时要额外显示的对象数目。

6.num_in_admin

添加对象时要显示的内联对象的默认个数。

7.raw_id_admin

为要键入的整数显示一个文本框,而不是一个下拉列表。在关联对象有很多行时,这个比显示 一个
列表选择框更实用。
使用 edit_inline 时,本项无效。

8.related_name

关联对象反向引用描述符。

9.to_field

关联对象的用于关联的字段,Django默认使用关联对象的主键。

一对一Model

有外键即设置关联关系的一方为从表,从表查主表为正向查询,反之。这里护照为从表,人为主表。

class Passport(models.Model): # 护照(从表)
note = models.CharField(max_length=20)
person = models.OneToOneField(to="Person",on_delete=models.CASCADE,null=True) #关系属性
class Meta:
db_table="t_passport"

class Person(models.Model): # 人(主表)
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta:
db_table="t_person"
注:不需要手动设置 person字段唯一,自动会设置为唯一

一对一 一个人一本护照

# 1.只查 单方数据 (与单表数据查询一致)
# 只查人的信息
ps = Person.objects.filter(name='Tom').values() # 自己查自己
print(ps)
# 只查 护照的信息
p1 = Passport.objects.all().values()
print(p1)
ps = Person.objects.filter(passport='1').values()
print(ps)

# 2.通过一方查另一方数据 (先获取一方数据,再通过它查询另一方)
# 查询 名字为tom的护照信息
p1 = Person.objects.get(name='Tom')
print(p1.passport.note) #反向查询 基于对象 类名小写
# 查询护照为美国的人的信息
ps = Passport.objects.get(note='美国')
print(ps.per_id, ps.per.name,ps.per.age) #正向查询 基于对象 直接调用外键

# 3.通过一方 查另一方 (查询条件是对方)
# 查询名字为tom的护照信息
p1 = Passport.objects.filter(per__name='Tom').values() #正向查询 基于字段 外键__字段
print(p1)
# 查询护照为美国的人的信息
p1 = Person.objects.filter(passport__note='美国').values() #反向查询 基于字段 类小写__字段
print(p1)
print(Person.objects.filter(passport__note='美国')) # QuerySet集合对象

# 4.保留双方数据 ()
# 查询名字为Tom的人信息 和 护照的信息
p1 = Person.objects.filter(name='Tom').values('name','age','passport__note') #反向查询 基于字段 类小写__字段
print(p1)
p1 = Passport.objects.filter(per__name='Tom').values('note','per__name','per__age','per_id') #正向查询 基于字段 外键__字段
print(p1)

一对一查询总结:

正向查询时,基于对象,对象.直接调用外键;基于字段 外键__字段

反向查询时,基于对象,对象.类名小写;基于字段 类小写__字段

感觉从表和主表查起来差不多。

一对多Model

货物为从表,种类为主表

class Category(models.Model): #种类(主表)
title = models.CharField(max_length=20)
note = models.CharField(max_length=20)
class Meta:
db_table="t_category"

class Goods(models.Model): #货物(从表)
title = models.CharField(max_length=20,unique=True)
price = models.FloatField()
cate = models.ForeignKey(to=Category,on_delete=models.CASCADE) #关系属性 主表删除后,从表中使用主表中数据的也会跟随一起删除
class Meta:
db_table = "t_goods"

# 1对多关系 Category(1):没有关系属性 Goods(*):其中有关系属性cate
# 一对多 查询 category主表 goods从表

# 1.只查询一方数据
# 只查 主表
c1 = Category.objects.filter(name='服装').values()
print(c1)
g1 = Goods.objects.filter(price=5000).values()
print(g1)

# 2.通过一方查询另一方 (先查询到一方数据,再通过它查询另一方)
# 查询服装类别为男装的 商品名称
c1 = Category.objects.get(name='服装')
print(c1.goods_set) # 查询也是一个集合 #反向查询 基于对象 对象.表名_set
print(c1.goods_set.all()) # 查询也是一个集合
# 查询 商品沙发所属的类别
g1 = Goods.objects.get(title='沙发')
print(g1.cate.name, g1.cate.note) #正向查询 基于对象 对象.外键.字段

# 3.通过一方查询另一方(查询条件是另一方)
# 查询 床 商品的 类别信息
c1 = Category.objects.filter(goods__title='床').values() #反向查询 基于字段 表名__字段
print(c1)
# 查询分类为 家居 类别的 商品信息
g1 = Goods.objects.filter(cate__name='家居').values() #正向查询 基于字段 外键__字段
print(g1)

# 4.保留双方数据
# 查询商品名称为 电视 的分类信息 和 商品信息
c1 = Category.objects.filter(goods__title='电视').values('name','note','goods__title','goods__price') #反向查询 基于字段 表名__字段
print(c1)
# 查询商品价格大于5000的商品的分类信息
c1 = Category.objects.filter(goods__price__gt=5000) #反向查询 基于字段 表名__字段
print(c1)
print(set(c1))

#注意在进行联合查询时,可能会由重复数据出现,解决:
list(set(Category.objects.filter(goods__price__gt=200)))

一对多总结:

正向查询时,基于对象,对象.外键.字段;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

多对多Model

class Student(models.Model): #学生(主表)
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta:
db_table="t_student"

class Course(models.Model): #课程(从表)
title = models.CharField(max_length=30)
expire = models.SmallIntegerField()
stu = models.ManyToManyField(to=Student) #关系属性
class Meta:
db_table="t_course"

# 多对多关系 Course:有对方关系属性students, Student:没有对方关系属性

# 1.只查询一方
# 查询学生 linda 学生信息
s1 = Student.objects.filter(name='Linda').values()
print(s1)
# 查询mysql课程信息
c1 = Course.objects.filter(title__icontains='MYSQL').values()
print(c1)

# 2.查询一方,通过它查询另一方
# 查询 学习mysql的学生信息
c1 = Course.objects.get(title='DJANGO')
print(c1.stu.all()) #正向查询 基于对象 对象.外键
# 查询 学生 linda 课程信息
s1 = Student.objects.get(name='Linda')
print(s1.course_set.all()) #反向查询 基于对象 对象.表名_set
print(s1.course_set.values())

# 3.通过一方 查询 另一方 (查询条件为对方)
# 查询 学生 linda 课程信息
c1 = Course.objects.filter(stu__name='Linda').values() #正向查询 基于字段 外键__字段
print(c1)
# 查询 学习mysql的学生信息
s1 = Student.objects.filter(course__title='PYTHON').values() #反向查询 基于字段 表名__字段
print(s1)


# 4.保留双方数据
# 查询学习django的学生信息 和 课程信息
s1 = Student.objects.filter(course__title='DJANGO').values('name','age','course__title','course__expire') #反向查询 基于字段 表名__字段
print(s1)
# 查询jack学习的课程信息 和 学生信息
c1 = Course.objects.filter(stu__name='Jack').values('title','expire','stu__age','stu__name') #正向查询 基于字段 外键__字段
print(c1)


#关联查询
Student.objects.filter(course__title__contains="h") #标题中含有"h"的课程中的学生 #反向查询 基于字段 表名__字段
Course.objects.filter(stu__name="zzz") #姓名为zzz的学生参加的课程 #正向查询 基于字段 外键__字段
Course.objects.filter(stu__age__gt=18) #年龄大于18的学生参加的课程 #正向查询 基于字段 外键__字段
坑:不能查具体某个字段

多对多总结:

正向查询时,基于对象,对象.外键;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

最后3个总结写在一起比较:

一对一查询总结:

正向查询时,基于对象,对象.直接调用外键;基于字段 外键__字段

反向查询时,基于对象,对象.类名小写;基于字段 类小写__字段

一对多总结:

正向查询时,基于对象,对象.外键.字段;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

多对多总结:

正向查询时,基于对象,对象.外键;基于字段,外键__字段

反向查询时,基于对象,对象.表名_set;基于字段,表名__字段

最后总结,

基于对象的情况下,正向查询时基本一致,直接调用外键就好;反向查询时一对多和多对多,需要对象.表名_set调用。

基于字段的情况下,正向查询时,外键__字段;反向查询时,表名__字段。一对一可能为类名小写__字段。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值