Django进阶,必须深刻了解Django的MTV模式。
M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。
V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template。
1. Django的字段概念解析
Model模型,负责对象和数据库的关系映射,所以Model本质是Python的数据类型,但它代表的是一个数据库的数据表。
数据库表格中有非常多的字段,例如char、varchar、date、datetime、text、int等,那在Model当中,也会有对应的类型,如:CharField、IntegerField、TextField;
以表格形式展示:
类型 | 说明 | 参数 |
---|---|---|
CharField | 字符串类型 | max_length、null、blank |
IntegerField | 整数类型 | int、null、blank |
TextField | 文本类型 | text、null、blank |
BooleanField | 布尔类型 | null、blank |
EmailField | 带邮箱检测的字符串类型 | null、blank |
当然还有一些本质和数据库类型是一样的,只是Django对他进行了很好的模拟,让开发者在使用的时候,可以更方便的写业务需求,而撇开本质上的数据类型纠结,如:ImageField、FileField、URLField,如下表格(还有很多):
类型 | 说明 | 参数 |
---|---|---|
ImageField | 字符串类型 | upload_to*、height_field、width_field |
FileField | 字符串类型 | upload_to* |
IPAddressField | 字符串类型 | null、blank |
URLField | 字符串类型 | null、blank |
数据库里面有外键的一个设置,可供sql的联合查询,但是Django有更强大的一个逻辑查询,一对一、多对一、多对多的关系,下面一个表格介绍下Django 的关系字段:
类型 | 关系 | 说明 |
---|---|---|
OneToOneField | 一对一 | 直接关联,查询直接返回对象 |
ForeignKey | 多对一 | 查询返回对象的列表集合 |
ManyToManyField | 多对多 | 查询返回对象的列表集合 |
2. 博客项目的实践操作
Django自带的UserModel字段有账户、密码、邮箱、FirstName、LastName、用户权限、组、最后登陆时间、注册时间、活跃状态、超级管理员选项、管理员登陆状态这几项,当然这无法满足一些常见的业务需求,所以必须给User表进行一个拓展信息表....
3. 一对一关系的使用
设定一个一一对应的拓展信息表,使用字段是models.OneToOneField(),用来定义一对一关系。
简单理解,它与声明了 unique=True 的 ForeignKey 非常相似,不同的是使用反向关联的时候,得到的不是一个对象列表,而是一个单独的对象。
首先先来看最简单的一个拓展信息定义:
class UserProfile(models.Model): belong_to = models.OneToOneField(to=User, related_name='profile') address = models.CharField(max_length=500, default="you guess") def __str__(self): return 'username:'+self.belong_to.username+' address:'+self.address
-
使用OneToOneField,里面至少需要一个参数,是指定关联的Model类(这里是User)
-
OneToOneField的第二个参数是反向查询的,如果没有,则无法通过User查询到它的拓展信息(加上还是好的)
-
address是额外辅助使用的,User表里面没这个字段
通过makemigrations和migrate后,将Model注册到admin中,从admin界面查看管理,首先是正常关联:
在User已经关联了UserProfile的情况下,再次关联,则会报错,如图:
这也是一一对应的一个特性,无法重复关联。
4. 逻辑上的错误和技术上的方案
当然这点也很容易报错,逻辑出错类型有以下几点:
-
关联不存在,使用UserProfile查询belong_to或者User反向查询会报错
-
已经关联,重复创建关联会报错
-
如果User关联了UserProfile,而此时User注销后删除,UserProfile会出错
不过在OneToOneField定义的时候,也会考虑到这些问题,首先是解决第三个,User关联了UserProfile,这时删了User,UserProfile的关联对象失效,则UserProfile也会被删除,这是Django默认的级联删除。on_delete加不加无所谓,默认值就是None。
当on_delete为None时,Django默认会给on_delete赋值为models.CASCADE,绑定删除是执行级联删除的操作。
如下是一种不执行级联删除的操作,修改默认逻辑。如果User删除,对应的UserProfile改成Null,代码如下:
class UserProfile(models.Model): belong_to = models.OneToOneField(to=User, related_name='profile',on_delete=models.SET_NULL, null=True) address = models.CharField(max_length=500, default="you guess") def __str__(self): if self.belong_to: return 'username:'+self.belong_to.username+' address:'+self.address else: return 'address:'+self.address
允许设置NULL,就必须设置null=True。
另外两点,例如User存在,但是在没关联UserProfile使用profile属性是会报错的,这点的解决方案就是在新建User时,自动新建对应的UserProfile并关联。
5. 测试操作
测试结果很简单,登陆Admin界面,新建User、新建UserProfile、删除User,查看UserProfile的操作结果,如果是级联删除,UserProfile也会消失;
如果是设置为NULL,则在UserProfile的界面会出现一个叉叉的图标,点击会问你是否确定删除用户,如下图:
首发于《Crossin的编程教室》
以上就是本篇文章的全部介绍内容了
!放在最后
如果文章中有什么错误或者建议修改的地方,欢迎留言纠正和回复
如果你喜欢本篇文章,不妨关注一下我们的公众号,每周更新两篇原创技术文档,都是干货