5. Django学习笔记——Model连表结构

ORM核心知识回顾:

  django会根据代码中定义的类来自动生成数据库表,我们写的类就是表示数据库的表。根据这个类创建的对象是数据库表里的一行数据,其中,对象.id 对象.value 是每一行里的数据。

一对多:models.ForeignKey(其他表)
多对多:models.ManyToManyField(其他表)
一对一:models.OneToOneField(其他表)

应用场景

一对多: 当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)。
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】。
多对多: 在某表中创建一行数据时,有一个可以多选的下拉框。
例如:创建用户信息,需要为用户指定多个爱好。
一对一: 在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)。
例如:有个身份证表,有个person表。每个人只能有一张身份证,一张身份证也只能对应一个人,这就是一对一关系。

一对多关系,即外键

  为什么要用一对多。先来看一个例子。有一个用户信息表,其中有个用户类型字段,存储用户的用户类型。如下:

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    age = models.IntegerField()
    user_type = models.CharField(max_length=10)

  不使用外键时用户类型存储在每一行数据中。如使用外键则只需要存储关联表的id即可,能够节省大量的存储空间。同时使用外键有利于维持数据完整性和一致性。
当然也有缺点,数据库设计变的更复杂了。每次做DELETE 或者UPDATE都必须考虑外键约束。

刚才的例子使用外键的情况时,需要单独定义一个用户类型表:

class UserType(models.Model):
    caption = models.CharField(max_length=32)

class UserInfo(models.Model):
    user_type = models.ForeignKey('UserType')
    username = models.CharField(max_length=32)
    age = models.IntegerField()

我们约定:
正向操作: ForeignKey在UserInfo表里,如果根据UserInfo去操作就是正向操作。
反向操作: ForeignKey不在UserType里,如果根据UserType去操作就是反向操作。

一对多的关系的增删改查:

正向操作:


1)创建对象实例,然后调用save方法:

 obj = UserInfo(name='li', age=44, user_type_id=2)
 obj.save()

或者:

obj = UserInfo()
Obj.name = ‘li’
Obj.age = 44
Obj.user_type_id = 2
Obj.save()

2)使用create方法:

UserInfo.objects.create(name='li', age=44, user_type_id=2)

3)使用get_or_create方法,可以防止重复:

UserInfo.objects.get_or_create(name='li', age=55, user_type_id=2)

4)使用字典:

dic = {'name':'zhangsan','age':18,'user_type_id':3}
UserInfo.objects.create(**dic)

5)通过对象添加

usertype = UserType.objects.get(id=1)
UserInfo.objects.create(name='li', age=55, user_type=usertype)


和普通模式一样删除即可。如:

UserInfo.objects.filter(id=1).delete()


和普通模式一样修改即可。如:

UserInfo.objects.filter(id=2).update(user_type_id=4)


正向查找所有用户类型为钻石用户的用户,使用双下划线:

users = UserInfo.objects.filter(user_type__caption__contains='钻石')

正向获取关联表中的属性可以直接使用点.语法,比如获取users查询集中第一个用户的caption:

users[0].user_type.caption
反向操作:

(一般使用正向增即可)
通过usertype来创建userinfo:
1) 通过userinfo_set的create方法
#获取usertype实例

ut = UserType.objects.get(id=2)

#创建userinfo

ut.userinfo_set.create(name='smith',age=33)


删除操作可以在定义外键关系的时候,通过on_delete参数来配置删除时做的操作。
on_delete参数主要有以下几个可选值:

models.CASCADE	默认值,表示级联删除,即删除UserType时,相关联的UserInfo也会被删除。
models.PROTECT	保护模式, 阻止级联删除。
models.SET_NULL	置空模式   设为null,null=True参数必须具备
models.SET_DEFAULT 置默认值 设为默认值,default参数必须具备
models.SET()	删除的时候重新动态指向一个实体访问对应元素 ,可传函数
models.DO_NOTHING   什么也不做。

注意: 修改on_delete参数之后需要重新同步数据库,如果使用 python manage.py shell进行models操作,需要退出shell重新进入。


和普通模式一样,不会影响级联表。


通过usertype对象来查有哪些用户的类型为1。

obj = UserType.objects.get(id=1)
obj.userinfo_set.all() 

可以通过在定义foreignkey时指定related_name来修改默认的userinfo_set,比如指定related_name为info。

user_type = models.ForeignKey('UserType',related_name='info')

指定related_name之后,反向查的时候就变成了:

obj.info.all()

获取用户类型为1且用户名为shuaige的用户

obj.info.filter(username='shuaige')

外键关系中,django自动给usertype加了一个叫做userinfo的属性。使用双下划线,可以通过userinfo提供的信息来查usertype (了解)。

user_type_obj = UserType.objects.get(userinfo__username='zs')

1.2 多对多关系

针对多对多关系django会自动创建第三张表。
(在哪个当中要显示出另外一个的时候写manytomany)
用户和组是典型的多对多关系:

class Group(models.Model):
 	name = models.CharField(max_length=20)              
	def __str__(self):
		return self.name
		
class User(models.Model):
	name = models.CharField(max_length=64)
	password = models.CharField(max_length=64)
	groups = models.ManyToManyField(Group)
	def __str__(self):
		return self.name

创建完后会自动生成中间表。先需要分别添加两个表的用户,再进行添加中间组。

操作:
增:
先分别创建user和group, 再使用add关联

u = User(name='aa', password='123')
u.save()
g = UserGroup(name='g5')
g.save()

通过Manager对象使用add()方法

u.groups.add(g)  或  g.user_set.add(u)
group.user_set.add(User.objects.get(id=2))    

删:
和一对多类似,删除user或group会级联删除user_groups表中的关联数据(但是删除的时候不会影响另外一个表)。

改:
和一对多类似,只修改当前表。

查:
正向:
查询id=2的用户所在的所有组group

u = User.objects.get(id=2)
u.groups.all()

反向:
查询id=1的组中包含的所有用户

g = Group.objects.get(id=1)
g.user_set.all()

1.3 一对一关系

一对一不是数据库的一个连表操作,而是Django独有的一个连表操作。一对一关系相当于是特殊的一对多关系,只是相当于加了unique=True。
一个人只能有一张身份证,一张身份证对应一个人,是一个典型的一对一关系。

class IdCard(models.Model):
	idnum = models.IntegerField()
	def __str__(self):
		return str(self.idnum)

class Person(models.Model):
	idcard = models.OneToOneField(IdCard)
	name = models.CharField(max_length=20)
	def __str__(self):
		return self.name

创建对象的时候idcard直接创建先,然后创建person的时候直接给它name属性和一个idcard_id=指定的身份证id即可。
一对一关系比较简单。两种表互相都有对方。比如:

>>> lisi = Person.objects.get(id=3)
>>> lisi.idcard
<IdCard: 123456>
>>> ids = IdCard.objects.get(id=3)
>>> ids.person

由于是唯一的,所以直接.类名的小写就可以了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值