模型

定义类属性

Django会自动创建自动增长的主键字段
每个模型只能有一个主键如果使用选项设置某属性为主键字段后django不会再自动创建自动增长的主键
自动创建的主键列属性名为id 使用时可以使用pk代替 pk全拼为primary key
注意:pk是主键的别名,若主键名为id2,那么pk是id2的别名

属性命名限制

不能是python的保留关键字
不允许使用连续的下划线 这是由django的查询方式决定的
定义属性时需要指定字段类型 通过字段类型的参数指定选项
语法如下:
属性=models.字段类型(选项)

字段类型

使用时需要引入django.db.models
字段类型如下:
AutoField: 自动增长的IntegerField 不指定值时Django会自动创建属性名为id的自动增长属性
BooleanField: 布尔字段 值为 True或False
NullBooleanField: 支持Null True False三种值
CharField(max_length=num): 字符串 必须设置长度
参数max_length表示最大字符数
TextField: 大文本 一般超过4000时使用
IntegerField: 整数
DecimalField(max_digits=None, decimal_places=None): 可以指定精度的十进制浮点数
参数max_digits 表示总位数
参数decimal_places 表示小数位数
FloatField: 浮点数
DateField([auto_now=False,auto_now_add=False]): 日期
参数auto_now表示每次保存对象时 自动设置当前时间默认为false
参数auto_now_add表示第一次被创建时自动设置当前时间flase
参数auto_now_add 和auto_now 是相互排斥的 组合将会发生错误
TimeField: 时间 参数和DateField一样
DateTimeField: 日期时间 参数同DateField一样
FileField: 上传文件字段 以二进制的形式
ImageField: 继承于FileField 对上传内容进行校验 确保是有效的图片
DecimalField 精度比 FloatField 要高 这是由底层存储方式决定的

选项

通过选项实现对字段的约束 选项如下:
null: 如果为True 表示允许为空 默认False
blank: 如果是True 表示允许为空白 默认False
null是数据库范畴的概念 blank是表单验证的范畴(如果仅null=True 在后台输入表单更新字段时表单验证会提示不能为空)
primary_key: 若为True 则表示字段会成为模型的主键字段 默认值False 一般作为AutoField的选项使用
如果使用选项设置某些属性为主键字段后 Django将不会创建自动增长的名为id的主键字段
unique: 若为True 则表示这个字段的记录的值必须唯一 默认是False
db_index: 若为True 则表示会为此字段创建索引 默认值为False
default: 默认值 可以是值或可调用对象
db_column: 表中字段的名称 如果未指定 则使用类属性的名称
只限于数据库表中的名字 操作模型类还是使用类属性的名字

字段查询

查询 通过 模型类.objects.过滤器函数()
字段查询 通过 模型类.objects.过滤器函数(属性名称__比较运算符=值)

过滤器函数

get() 返回满足条件的对象 是一个普通对象

  • 如果查询到多条数据则抛出 MultipleObjectsReturned
  • 查询不到内容则抛出 DoesNotExist

all() 返回所有对象 是一个QuerySet对象
filter() 返回满足条件的对象 是一个QuerySet对象
exclude() 返回不满足条件的对象 是一个QuerySet对象
order_by() 返回QuerySet对象的排序结果 是一个QuerySet对象
aggregate(聚合) 返回QuerySet对象聚合函数后的结果 是一个Python字典
count() 返回结果对象或QuerySet对象的统计个数 是一个整型 注意: 这个函数没有参数
exists() 返回QuerySet对象是否有数据 是一个布尔类型(True非空 False空) 注意:这个函数没有参数
QertySet 对象可以继续使用以上过滤器函数查询

条件运算符

等查询

判等 __exact

BookInfo.objects.get(id__exact=1)
简写为:
BookInfo.objects.get(id=1)
模糊查询

包含 __contains

BookInfo.objects.filter(btitle__contains="传")

开头或结尾 __startswith | __endswith

BookInfo.objects.filter(btitle__startswith="天")
BookInfo.objects.filter(btitle__endswith="部")

以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexacticontainsistartswithiendswith

空查询

__isnull=True

BookInfo.objects.filter(btitle__isnull=False)

范围查询

范围 __in=[]

BookInfo.objects.filter(id__in=[1,3,5])

比较查询

gt 大于 lt 小于 gte 大于等于 lte 小于等于

BookInfo.objects.filter(id__gt=3)

不等于 exclude()过滤器

BookInfo.objects.exclude(id__exact=3)
日期查询

year、month、day、week_day、hour、minute、second

BookInfo.objects.filter(bpub_date__year=1980)
from datetime import date
BookInfo.objects.filter(bpub_date__gt = date(1980,1,1))

排序

默认从小到大 ASC 输入- 从大到小 DESC
order_by的参数必须是字符串类型
可以对QuerySet查询集使用

排序 order_by()过滤器

BookInfo.objects.all().order_by("id", "btitle")
BookInfo.objects.filter(id__gt=3).order_by("-bread")

F对象

F(属性名)
用于类属性之间的比较
F对象内输入的必须是字符串
F对象可以进行运算符运算

from django.db.models import F

例:查询阅读量大于评论量的对象

BookInfo.objects.filter(bread__gt=F("bcomment"))

例: 查询阅读量大于 二倍的评论量

BookInfo.objects.filter(bread__gt=F("bcomment")*2)

Q对象

Q(属性名__条件运算符=值)
用于查询时条件之间的逻辑关系
使用Q创建一个对象在Q对象前输入 & | ~ 表示 and or not

from django.db.models import Q

and

BookInfo.objects.filter(id=1, btitle="天龙八部")
或
BookInfo.objects.filter(Q(id=1)&Q(btitle="天龙八部"))

or

BookInfo.objects.filter(Q(id=1)|Q(btitle="雪山飞狐"))

not

BookInfo.objects.exclude(id__gt=3)
或
BookInfo.objects.filter(~Q(id__gt=3))

一般在需要使用or关系时才使用Q对象

聚合函数

aggregate()过滤器来调用聚合函数
返回一个字典{'聚合类名小写__属性名':值} 格式如: {'sum__bread':3}
使用前 需要从django.db.models 导入聚合类
聚合函数的参数必须是字符串

from django.db.models import Sum, Count, Max, Min, Avg

例:查询所有图书的数目

BookInfo.objects.all().aggregate(Count("id"))
返回{'id__count': 8}

例:查询所有图书阅读量的总和

BookInfo.objects.all().aggregate(Sum("bread"))
返回{'bread__sum': 126}

count()过滤器

统计满足条件的数据数目
返回值是一个整型

例:统计所有图书的数目

BookInfo.objects.all().count()

例:统计ID大于3的所有图书数目

BookInfo.objects.filter(id__gt=3).count()

查询集

管理器上调用某些过滤器方法会返回查询集 查询集结果可以有零个 一个多个
从Sql的角度,查询集和select语句等价,过滤器像where和limit子句
QuerySet对象在Django中叫做查询集 表示查询到的多条数据表记录的集合
QuerySet可以遍历 且 可以写入多个条件
QuerySet对象可以继续应用all filter excloud order_by 等所有过滤器

BookInfo.objects 管理器 是一个Manager的对象
BookInfo.objects.get(id=1) 表示一条记录
BookInfo.objects.all()|filter()|exclude()|order_by(id) 表示多条数据 是一个QertySet对象
对任何管理器.all()查询的结果使用过滤器时可以省略all() 如: BookInfo.objects.count()

返回单个值的过滤器如下

  • get():返回单个满足条件的对象

    • 如果未找到会引发模型类.DoesNotExist异常
    • 如果多条被返回会引发模型类.MultipleObjectsReturned异常
  • count():返回当前查询结果的总条数

  • aggregate():聚合,返回一个字典

返回查询集的过滤器如下

  • all():返回所有数据。
  • filter():返回满足条件的数据。
  • exclude():返回满足条件之外的数据,相当于sql语句中where部分的not关键字。
  • order_by():对结果进行排序。

判断某一个查询集中是否有数据

  • exists():判断查询集中是否有数据,如果有则返回True,没有则返回False。

两大特性

1.惰性查询
只有在实际使用时才真正的对数据库进行操作(创建查询集对象时 不实际操作数据表)
而真正调用数据表的情况包括迭代序列化与if合用(针对查询集对象使用以上操作时才实际操作数据表)
2.缓存
每个查询集都包含一个缓存来最小化对数据库的访问
第一次使用时查询数据库 并把结果缓存起来
再次使用时不会查询数据库而是使用缓存的结果

books = BookInfo.objects.filter(btitle__isnull)  实际不查询数据库
[book for book in books] 第一次使用 实际查询数据库
[book for book in books] 再次使用 实际不查询数据库

限制查询集

可以对查询集进行取下标或切片操作,等同于sql中的limit和offset子句

但是不同于列表 不可以使用负值切片和取值

例: 获取1,2两个对象 返回一个QuerySet 查询集

BookInfo.objects.all()[0:2]
注意

获取一个对象使用QuerySet[0] 等价于 QuerySet[0:1].get()
QuerySet[0] 返回普通对象QuerySet[0:1] 返回只有一个值的QuerySet对象
对只有一个值的查询集对象使用get()会得到一个普通对象
如果没有数据,QuerySet[0]引发IndexError异常
如果没有数据,QuerySet[0:1].get()引发DoesNotExist异常

模型类关系

一对应的类叫做一类
多对应的类叫做多类
把用来建立关联的类属性叫做关联属性

关系字段类型

关系型数据库的关系包括三种类型:
ForeignKey:一对多,将字段定义在多的一端
ManyToManyField:多对多,将字段定义在任意一端
OneToOneField:一对一,将字段定义在任意一端
可以维护递归的关联关系,使用"self"指定,详见"自关联"

一对多关系

表1的某条记录对应表2的多条记录
表2的多条记录对应表1的一条记录
设置ForeignKey多类

hbook = models.models.ForignKey("一类表名")
多对多关系

表1的多条记录对应表1的多条记录
表2的多条记录对应表1的多条记录
设置ManyToManyField任意类

ntype = models.ManyToManyField("多类表名")
一对一关系

表1的某条记录对应表2的某条记录
表2的某条记录对应表1的某条记录
设置OneToOneField任意类

ebasic = models.OneToOneField("一类表名")

关联查询(一对多)

实现类似于inner join 查询
例: 查询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)

hbook对应的是一个在HeroInfo类中被关联的模型类
heroinfo对应的也是一个在BookInfo类中被关联的模型类
而由于 heroinfo 属于多类 所以heroinfo 有一个heroinfo_set 代表包含所有heroinfo对象的QuerySet
同理多对多关系中 互相都有_set属性 用来代表互相被关联的模型类的对象的QuerySet集合

查询HeroInfo 通过BookInfo关联的heroinfo 实现inner join
例: 获得图书信息,通过英雄描述

BookInfo.objects.filter(heroinfo__hcomment="降龙十八掌")

查询Bookinfo 通过Heroinfo关联的hbook 实现inner join
例: 获得英雄信息,通过图书标题

HeroInfo.objects.filter(hbook__btitle="天龙八部")
模型_第1张图片
关联查询.png

自关联

自关联的本质是一种特殊的一对多关系
省--市--县
省对于市属于一对多关系
市对于县属于一对多关系
设置类属性外键关联自身主键完成自关联
关联属性 = ForignKey("self", on_delete=models.CASCADE)
输入"self"代表自身对象 也可以输入自身模型类名

class AreaInfo(models.Molde):
    id = AutoField(primary_key=True)
    name = CharField(max_length=20)
    parent = ForignKey("self", null=True, blank=True, on_delete=models.CASCADE)

物理上的一张表 逻辑上的三张表
省对象 市对象 县对象的 areainfo_set 和 parent 代表的内容不同

管理器

Django默认会为每个模型类生成一个objects管理器对象
通过管理器可以实现对模型类对应数据表的查询
objects是models.Manger类的一个对象
手动定义管理器后Django不再自动生成模型类的管理器对象

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    
    objects = models.Manage()  # 定义后 Django 将不再自动生成objects

此objects 非 自动生成的objects 可以随意改变管理器对象的变量名

自定义管理器类

1.创建一个管理器类继承models.Manage
2.在模型类中通过新管理器类创建一个管理器对象

重写管理器类的应用场景:
1.改变查询集结果
# 重写管理器类
class BookInfoManage(models.Manager):
    def all(self):  # 重写all()方法
        res = super(BookInfoManage, self).all()  # 调用父类方法实现
        res = res.filter(isDelete=0)  # res是一个QuerySet 可以继续使用过滤器
        return res  # 将改变后的结果return 

# 通过自定义管理器类创建新的管理器对象
class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    isDelete = models.BooleanField(default=False)

    objects = BookInfoManage()  # 此objects 非自动创建的管理器

然后再通过BookInfo.objects查询到的结果就是修改后返回的查询集了

2.添加额外方法

1.通过在模型类中使用类方法来得到的引用
2.通过模型类的引用创建实例对象
3.操作实例对象返回结果

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    isDelete = models.BooleanField(default=False)

    @classmethod
    def create_book(cls, btitle, isDelete)
        obj = cls()
        obj.btitle = btitle
        obj.isDelete = isDelete
        obj.save()
        return obj
# 使用额外方法
book = BookInfo.create_book("甄嬛传", True)

为了明确关系通常把这些方法定义在管理器类里
每个管理器对象都有self.model属性用来获取管理器类对应的模型类名(因为模型类调用了自定义的管理器类)

class BookInfoManage(models.Manager):
    def create_book(self, btitle)
        model_class = self.model # self.model是管理器对应的模型类的引用
        book = model_class() # 创建一个模型类对象
        book.btitle = btitle
        book.save()
        return book

# 通过自定义管理器类创建新的管理器对象
class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    isDelete = models.BooleanField(default=False)

    objects = BookInfoManage()  # 此objects 非自动创建的管理器
# 使用额外方法
BookInfo.objects.create_book("甄嬛传")
管理器的create方法

models.Manage提供的create方法通过关键字参数的方式创建一条表记录而不需要先创建模型类对象

book = BookInfo.objects.create(btitle="甄嬛传", bpub_date="1990-1-1")

返回一个模型类对象 对应这条添加的数据表记录

元选项

Django默认生成的表名

应用名小写_模型类名小写

注意

Django程序默认通过应用名小写_模型类名小写指向要操作的数据表
如果应用名发生改变Django将无法通过应用名找到对应的数据表因为数据表已经迁移完成
通过Meta指定表名后模型类调用数据表时将不再依赖于应用名而是通过db_table的值

元选项

在模型类中定义元类
修改元类的db_table类属性实现指定表名

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    isDelete = models.BooleanField(default=False)

    class Meta:
        db_table = "bookinfo"  # 修改元类的类属性修改表名

你可能感兴趣的:(模型)