【Django 笔记】模型
笔记主要基于官方文档,从中提取要点和记录笔记,关键处包含了官方文档链接。详见官方文档。
官方文档:Django documentation
博客推荐:Django2.2教程
官方文档模型层:The model layer 模型层
目录
1.关系
相关官方文档:关系类型 https://docs.djangoproject.com/zh-hans/2.2/topics/db/queries/#related-objects
https://www.liujiangblog.com/course/django/96
1.1.关系字段类型
关系型数据库的关系包括三种类型:
ForeignKey
:一对多,将字段定义在多的一端中。-
ManyToManyField
:多对多,将字段定义在任意一端中。 OneToOneField
:一对一,将字段定义在任意一端中。- 可以维护递归的关联关系,使用'self'指定,详见"自关联"。
1.1.1.一对多ForeignKey
One-to-many relationships多对一的关系,通常被称为ForeignKey外键。外键字段类的定义如下:
class
ForeignKey
(to, on_delete, **options)[源代码]
外键需要两个位置参数,一个是关联的模型(被关联的类)和 on_delete
选项。在Django2.0版本后, on_delete
选项为必填。
外键要定义在‘多’的一方: 如厂家生产很多车,则外键定义在车
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
若关联的对象在另外一个app中,可以用完整的应用标签显式的指出。
下例假设Manufacturer模型存在于production这个app中,则Car模型的定义如下:
class Car(models.Model):
manufacturer = models.ForeignKey(
'production.Manufacturer', # 关键在这里!!
on_delete=models.CASCADE,
)
如果要创建一个递归的外键,也就是自己关联自己的外键(自关联),使用下面的方法:
models.ForeignKey('self', on_delete=models.CASCADE)
核心在于‘self’这个引用。什么时候需要自己引用自己的外键呢?典型的例子就是评论系统!一条评论可以被很多人继续评论,如下所示:
class Comment(models.Model):
title = models.CharField(max_length=128)
text = models.TextField()
parent_comment = models.ForeignKey('self', on_delete=models.CASCADE)
# .....
注意上面的外键字段定义的是父评论,而不是子评论。为什么呢?因为外键要放在‘多’的一方!
类似的还有自关联的 地区的行政管理、公司部门的上下级部门行政级别管理等系统。
外键还有一些重要的参数,参考:外键参数
示例:多对一关联示例
1.1.2. 多对多ManyToManyField
多对多的字段可以定义在任何的一方,尽量定义在符合人们思维习惯的一方。字段类的定义如下:
class
ManyToManyField
(to, **options)[源代码]
多对多关系需要一个位置参数:关联的对象模型。它的用法和外键多对一基本类似。
class TypeInfo(models.Model):
# ...
pass
class NewsInfo(models.Model):
# ...
ntype = models.ManyToManyField('TypeInfo') #通过ManyToManyField建立TypeInfo类和NewsInfo类之间多对多的关系
注:在数据库后台,Django实际上会额外创建一张用于体现多对多关系的中间表。默认情况下,该表的名称是“多对多字段名+关联对象模型名+一个独一无二的哈希码”。例如‘author_books_9cdf4’,当然也可以通过
db_table
选项,自定义表名。
多对多还有一些重参数,参考:多对多参数
示例:多对多关联示例
1.1.3. 一对一OneToOneField
一对一关系类型的定义如下:
class
OneToOneField
(to, on_delete, parent_link=False, **options)[源代码]
一对一关系类似具有unique=True
属性的外键关系,但是反向关联对象只有一个。
该关系的第一位置参数为关联的模型,其用法和前面的多对一外键一样。
如果你没有给一对一关系设置related_name
参数,Django将使用当前模型的小写名作为默认值。
OneToOneField一对一关系拥有和多对一外键关系一样的额外可选参数,只是多了一个parent_link参数。
示例:一对一关联示例
1.2.关联查询(一对多)
1.2.1.查询和对象关联的数据
在一对多关系中,一对应的类我们把它叫做一类,多对应的那个类我们把它叫做多类,我们把多类中定义的建立关联的类属性叫做关联属性(关系属性、关系字段)。
以下例子,假设,一本书(一类BookInfo)对应多个英雄(多类HeroInfo)。
由一类的对象查询多类的时候(由一到多的访问语法):一类的对象.多类名小写_set.
一类的对象.多类名小写_set.all()
# 查询id为1的图书关联的英雄的信息
b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()
# 通过模型类查询:
HeroInfo.objects.filter(hbook__id=1)
由多类的对象查询一类的时候:多类的对象.关联属性
多类的对象.关联属性
# 查询id为1的英雄关联的图书信息
h = HeroInfo.objects.get(id=1)
h.hbook
# 通过模型类查询:
BookInfo.objects.filter(heroinfo__id=1)
由多类的对象查询一类对象的id时候:多类的对象. 关联属性_id
多类的对象. 关联属性_id
h = HeroInfo.objects.get(id=1)
h.hbook_id
1.2.2.通过模型类实现关联查询
通过多类的条件查询一类的数据:
一类名.objects.filter(多类名小写__多类属性名__条件运算符=值)
通过一类的条件查询多类的数据:
多类名.objects.filter(关联属性__一类属性名__条件运算符=值)
Tips:
- 通过模型类实现关联查询时,要查哪个表中的数据,就需要通过哪个类来查。
- 写关联查询条件的时候,如果类中没有关系属性,条件需要写对应类的名。如果类中有关系属性,直接写关系属性。
例子:
例:查询图书信息,要求图书关联的英雄的描述包含'八'。
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
例:查询图书信息,要求图书中的英雄的id大于3.
BookInfo.objects.filter(heroinfo__id__gt=3)
例:查询书名为“天龙八部”的所有英雄。
HeroInfo.objects.filter(hbook__btitle='天龙八部')
1.3.插入、更新和删除
调用一个模型类对象的save方法的时候就可以实现对模型类对应数据表的插入和更新。
调用一个模型类对象的delete方法的时候就可以实现对模型类对应数据表数据的删除。
1.4.自关联
自关联:自关联
自关联是一种特殊的一对多关系。
说明:关系属性使用self指向本类,要求null和blank允许为空,因为一级数据是没有父级的。
要创建一个递归关系 -- 一个与其自身有多对一关系的对象 -- 则使用 models.ForeignKey('self', on_delete=models.CASCADE)
。
举例:地区信息模型类
#定义地区模型类,存储省、市、区县信息
class AreaInfo(models.Model):
atitle=models.CharField(max_length=30)#名称
aParent=models.ForeignKey('self',null=True,blank=True, on_delete=models.CASCADE)#关系
2.管理器
管理器官方文档:管理器
查询时,一般都用到objects,比如:模型类.objects.all(),那objects是一个什么东西呢?
答:objects是Django帮我自动生成的管理器对象,默认情况下,Django 为每个模型类添加了一个名为 objects
的 Manager
。通过这个管理器可以实现对数据的查询。objects是models.Manger类的一个对象。
管理器
管理器是Django的模型进行数据库操作的接口,Django应用的每个模型类都拥有至少一个管理器。Django支持自定义管理器类,继承自models.Manager。
自定义管理器
当没有为模型类定义管理器时,Django会为每一个模型类生成一个名为objects的管理器,自定义管理器后,Django不再生成默认管理器objects。
继承基类 Manager
,在模型中实例化自定义 Manager
,你就可以在该模型中使用自定义的 Manager
。
自定义Manager主要用于两种情况:
1.改变查询的结果集,即修改 Manager
返回的原始 QuerySet。
比如重写all()方法。
2.向管理器类中添加额外的Manager
方法,如封装方法,操作模型类对应的数据表(增删改查)。
注:
Manager
方法能通过self.model()
获取所依附的模型类,使用self.model()就可以创建一个跟自定义管理器对应的模型类对象。在自定义的Manager里使用,这样就避免了模型类名发生变化时,需要改自定义Manager的代码。
举例:
class BookInfoManager(models.Manager):
'''图书模型管理器类'''
# 1.改变原有查询的结果集
def all(self):
# 1.调用父类的all方法,获取所有数据
books = super().all() # QuerySet
# 2.对books中的数据进行过滤
books = books.filter(isDelete=False)
# 返回books
return books
# 2.封装方法,操作模型类对应的数据表(增删改查)
def create_book(self, btitle, bpub_date):
'''添加一本图书'''
# 1.创建一个图书对象
# 获取self所在的模型类
model_class = self.model
book = model_class()
book.btitle = btitle
book.bpub_date = bpub_date
# 2.添加进数据库
book.save()
# 3.返回book
return book
class BookInfo(models.Model):
# ...省略
objects = BookInfoManager() # 自定义一个BookInfoManager类的对象
模型管理器类和模型类关系
如图:模型类的objects就是模型管理类Manager的实例对象。模型类的实例对象可以通过objects调用Manager的方法...
更多Manager详情移步官方文档:https://docs.djangoproject.com/zh-hans/2.2/topics/db/managers/#
3. 元选项
官方文档:Meta 选项、Model Meta options
相关博文:https://www.liujiangblog.com/course/django/99
模型的元数据,指的是“除了字段外的所有内容”,例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的,甚至元数据本身对模型也是非必须的。
利用元类Mate指定表名
Django默认生成的表名:
<app_name>_<model_name> 即 应用名小写_模型类名小写
但在Django中,默认生成的表名如上。当模型名改了之后,对应的表名也会改变,这时用新的表名去找旧的数据就会报错。要表名不依赖于应用和模型类的名字,就需要指定表名。
在模型类中定义一个元类Meta,在里面定义一个类属性db_table就可以指定表名。如下:
# 定义图书模型类BookInfo
class BookInfo(models.Model):
# ...省略
# 定义元选项
class Meta:
db_table='bookinfo' # 指定BookInfo生成的数据表名为bookinfo
重新执行迁移之后,表名就是 bookinfo 了。
模型中增加元数据
有上面的例子可见,想在模型中增加元数据,方法很简单,在模型类中添加一个子类,名字是固定的Meta
,然后在这个Meta类下面增加各种元数据选项或者说设置项。
强调:每个模型都可以有自己的元数据类,每个元数据类也只对自己所在模型起作用。
可用的元数据选项:参考 Available Meta options
回归原生 SQL
若你发现需要编写的 SQL 查询语句太过复杂,以至于 Django 的数据库映射无法处理,你可以回归手动编写 SQL。Django 针对编写原生 SQL 有几个选项;参考 执行原生 SQL 查询。
最后,Django 数据库层只是一种访问数据库的接口,理解这点非常重要。你也可以通过其它工具,编程语言或数据库框架访问数据库;Django 并没有对数据库数据库做啥独有的操作。
-----end-----