Model的字段解析和一对一关系实践

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界面查看管理,首先是正常关联:

Model的字段解析和一对一关系实践_第1张图片

在User已经关联了UserProfile的情况下,再次关联,则会报错,如图:

Model的字段解析和一对一关系实践_第2张图片

这也是一一对应的一个特性,无法重复关联。

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的界面会出现一个叉叉的图标,点击会问你是否确定删除用户,如下图:

Model的字段解析和一对一关系实践_第3张图片

 

 

首发于《Crossin的编程教室》

 

 


以上就是本篇文章的全部介绍内容了


 

!放在最后

 

如果文章中有什么错误或者建议修改的地方,欢迎留言纠正和回复

 

如果你喜欢本篇文章,不妨关注一下我们的公众号,每周更新两篇原创技术文档,都是干货

你可能感兴趣的:(Spbeen,Django2,爬虫教程)