一、ORM简介
在MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,及数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松的更换数据库。
ORM是“对象-关系-映射”的简称,主要任务是:
1.)根据对象的类型生成表结构
2.)将对象、列表的操作,转换为sql语句
3.)将sql查询的结构转换成对象、列表
Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表
二、数据库 MySQL
这里选用MySQL
在项目中settings.py配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'testone',
'USER': 'joker',
'PASSWORD': 'xxx2',
'HOST': '127.0.0.1',
'PORT': '3306'
}
}
三 新建项目-用来之后测试
1.) 使用虚拟环境,之后选择一个,我这里使用自己创建好的
workon my-cross
2.) 创建django项目
django-admin startproject testone
3.) 在mysql中创建一个数据库 这里和上面的配置NAME‘必须对应 ,testone,
四 开发流程初探
1.) 在models.py中定义模型类,要求继承models.Model
2.) 把应用加入settings.py文件的installed_app项
3.) 生成迁移文件
4.) 执行迁移文件
5.) 使用模型类进行数据库的增删改查操作。
五 定义模型
在模型中定义属性,会生成表中的字段
django根据属性的类型确定一下信息:
1)当前选择的数据库支持字段的类型
2)渲染管理表单时使用的默认html空间
3)在管理站点最低限度的验证
django会为表增加自动增长字段的主键列,如果自行设置了主键列,默认就不生成
属性命名限制:
1. 不能是python的保留字
2. 由于django的查询方式,不允许使用连续的下划线
(1) 创建一个应用-用来之后的测试
python manage.py startapp booktest
创建了一个booktest的应用,
将应用加入到settings.py中
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'booktest' #新增
]
(2) 定义属性:
定义属性时,需要字段类型
字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中
使用方式
1. 导入from django.db import models
2. 通过models.Field创建字段类型的对象,赋值给属性
对于重要的数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
(3)字段类型、选项和关系:
https://docs.djangoproject.com/zh-hans/2.1/ref/models/fields/
(4)元数据
在模型类中定义类Meta,用来设置元信息
元信息:
db_table:定义数据表名称,使用小写。
ordering:对象的默认排序字符,获取对象的列表时使用,接受属性构成的里列表
可以加 - , 不加 - 表示正序
(5)添加models.py中的类
from django.db import models
# Create your models here.
class BookInfo(models.Model):
title = models.CharField(max_length=20)
public = models.DateTimeField()
reads = models.IntegerField(default=0)
commet = models.IntegerField(null=False)
isDelete = models.BooleanField(default=False)
class Meta:
db_table = 'bookinfo'
class HeroInfo(models.Model):
name = models.CharField(max_length=10)
gender = models.BooleanField(default=True)
content = models.CharField(max_length=1000)
isDelete = models.BooleanField(default=False)
book = models.ForeignKey(BookInfo,on_delete=models.CASCADE)
"""测试
insert into bookinfo(title,public,reads,commet,isDelete) values
('射雕英雄传','1980-05-01',12,34,0),
('天龙八部','1986-07-24',46,32,0),
('笑傲江湖','1995-12-14',30,50,0);
"""
"""
insert into booktest_heroinfo(name,gender,book_id,content,isDelete) values
('郭靖',1,1,'降龙十八章',0),
('黄蓉',0,1,'打狗棒法',0),
('黄药师',1,1,'弹指神通',0),
('欧阳锋',1,1,'蛤蟆功',0),
('梅超风',0,1,'九阴白骨爪',0),
('乔峰',1,2,'降龙掌',0),
('段誉',1,2,'六脉神剑',0),
('虚竹',1,2,'六阳掌',0),
('王语嫣',0,2,'勾魂夺魄',0),
('令狐冲',1,3,'独孤九剑',0),
('任盈盈',0,3,'谈情说爱',0)
"""
生成迁移文件和执行迁移:
python manage.py makemigrations
python manage.py migrate
六 模型成员
(1) 类的属性
· objects:是Manager类型的对象,用于数据库及进行交互
· 当定义模型类时没有制定管理器,则django会为模型类提供要给名为objects的管理器
· 支持明确指定模型类的管理器
class BookInfo(models.Model):
...
books = models.Manager() #自定义管理器
当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器
(2) 管理器Manager
· 管理器是django的模型进行数据库的操作的接口,django每个模型都有一个管理器
· 自定义管理器:
一:向管理器类中添加额外方法,见下面"创建对象 "中的方式二
二:修改挂力气返回的数据集:重写get_queryset方法
class BookInfoManager(models.Manager):
def get_queryset(self):
return super(BookInfomanager,self).get_queryset().filter(isDelete=False)
class BookInfo(models.Model):
...
books = models.BookInfoManager() #自定义管理器
(3)创建对象
· 当创建对象时,django不会对数据库进行读写操作
· 调用save()方法与数据库进行交互,将对象保存到数据库中
(4) 模型类的创建方法:
class BookInfo(models.Model):
title = models.CharField(max_length=20)
public = models.DateTimeField()
reads = models.IntegerField(default=0)
commet = models.IntegerField(null=False)
isDelete = models.BooleanField(default=False)
class Meta:
db_table = 'bookinfo'
# 模型类的创建方法:
# 第一种:使用类方法(也可以使用对象方法)
@classmethod
def create(cls,title,public,reads,commet,isDelete):
book = BookInfo()
book.title = title
book.public = public
book.reads = reads
book.commet = commet
book.isDelete = isDelete
return book
#或者在自定义管理其中定义个create方法。
七 模型查询
在django中ORM就是django中的管理器,它来帮助我们操作数据库。
· 查询集表示从数据库中获取的对象集合
· 查询集可以包含零个、一个或多个过滤器
· 过滤器基于所给的参数显示查询结果
· 从sql的角度来说,查询集合select语句等价,过滤器类似where和limite等
(1) 查询集
· 在管理器上调用过滤器方法返回查询集
· 查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤
· 惰性执行: 创建查询集不会带来任何数据库的访问,直到调用数据时,才会访问数据库库
· 何时对查询及求值: 迭代,序列化,与if合用
· 返回查询集的方法,称为过滤器
all()
filter()
exclude()
order_by()
values():一个对象构成一个字典,然后构成一个列表返回。
写法:
filter(键1 = 值1 ,键2 = 值2 )
等同:
filter(键1 = 值1 ).filter(键2 = 值2 )
测试:python manage.py shell
>>> from booktest.models import BookInfo
>>> BookInfo.objects.values() #这样就打印了结果
返回单个值的方法:
· get(): 返回单个满足条件的对象
如果未找到,报异常
如果返回多条,报异常
· count():返回当前查询的总条数
· first(0 返回第一个对象
· last()
· exists():判断查询集中是否有数据u,如果有则返回true
限制查询集
· 查询及返回列表,可以使用下标的方式进行限制,等同于sql中的limit和offset子句
· 注意: 不支持负数索引
· 使用下标后返回一个新的查询集,不会立即执行查询
. 如果获取一个对象,直接使用[0],等同于[0:1].get() ,但是如果没有数据,[0]会引发indexError一次,[0:1].get()引发doesnotExist异常
查询集的缓存:
· 每个查询都包含一个缓存来最小化对数据库的访问
· 在新建的查询集中,缓存为空,首次对查询集求职时,会发生数据库查询,django会将查询的结果存在查询
集的缓存中,并返回请求的结果,接下来对查询集求职将重用缓存的结果
情况一: 构成了连个查询集,无法重用缓存,每次查询都会与数据库进行一次交换,增加负载
print([e.title for e in Entry.objects.all()])
print([e.title for e in Entry.objects.all()])
情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
querylist = Entry.objects.all()
print([e.title for e in Entry.objects.all()])
print([e.title for e in Entry.objects.all()])
何时查询集不会被缓存: 当子对查询集的部分进行求值是会检查缓存,如果这部分不再缓存中,那么接下来的查询返回的记录将不会被缓存,这意味着使用索引来限制查询集将不会填充缓存。
字段查询
· 实现where子句,作为方法filter() 、exclude() 、get()参数
· 语法:属性名称_比较运算符 = 值
· 表示两个下划线,左侧是属性名称,右侧是比较类型
· 对于外键,使用属性名_id表示外键的原始值
· 转义 :like语句中使用%, 匹配数据中的%,在过滤器中直接写,如:
filter(title__contains="%")等价于where title like '%\%%'表示查找标题中包含%的
比较运算符:
默认有:exact:表示判断是否相等,大小写敏感,如果没有写 比较运算符,表示判断相等
>>> BookInfo.objects.filter(isDelete = False)
<QuerySet [<BookInfo: BookInfo object (1)>, <BookInfo: BookInfo object (2)>, <BookInfo: BookInfo object (3)>]>
>>> BookInfo.objects.filter(isDelete = True)
<QuerySet []>
包含:contains:是否包含,大小写敏感
>>> BookInfo.objects.filter(title__contains="天龙八部")
<QuerySet [<BookInfo: BookInfo object (2)>]>
startswith ,endswith:以value开头或结尾,大小写敏感
>>> BookInfo.objects.exclude(title__endswith="部")
<QuerySet [<BookInfo: BookInfo object (1)>, <BookInfo: BookInfo object (3)>]>
isnull, isnotnull:是否为null
在前面加个i表示不区分大小写,iexact,icontains,istartswith,iendswith
in:是否在包含范围内
filter(id__in=[1,2,3,4])
gt ,gte,lt,lte:大于,大于等于,小于,小于等于
filter(id__gt=3)
year,month,day,week_day,hour,minute,seconde:对日期类型的属性进行运算
filter(public__year=1980)
filter(public__gt = date(1980,12,31))
跨关联关系的查询:处理join查询
语法:模型类名<属性名><比较运算符>
注:可以没有__<比较>部分,表示等于,结果同inner join
可反向使用,即在关联的两个模型中都可以使用
filter(heroinfo__content__contains="八" )
查询的快捷方式:pk,pk表示primary key,默认主键是id
filter(pk__lt =6)
聚合函数:
· 使用aggregate()函数返回聚合函数的值
· 函数: Avg, Count ,Max ,Min ,Sum
from django.db.models import Max
maxDate = list.aggregate(Max('public'))
F对象
可以使用模型的字段A与字段B进行比较,如果A写在等号的左侧,则B出现在等号的右侧,需要通过F对象构造
list.filter(read_gte=F('commet'))
Q对象:
· 过滤器的方法中关键参数查询,会合并为And进行
· 需要进行or查询,使用Q()对象
· Q对象(django.db.models,Q)用于封装一组关键字参数,这些参数与 比较运算符中的相同。
#可以使用&( and) 和 | (or)操作
#~表示去放(~Q(pk__lt=6))
from django.db.models import Q
list.filter(pk__lt=6).filter(commet__gt=10)
list.filter(Q(pk__lt)=6 | Q(commet__gt=10))
八 增删改查示例
查-
models.UserInfo.objects.all()
models.UserInfo.objects.all().values('user') #只取user列
models.UserInfo.objects.all().values_list('id','user') #取出id和user列,并生成一个列表
models.UserInfo.objects.get(id=1)
models.UserInfo.objects.get(user='yangmv')
增:
models.UserInfo.objects.create(user='yangmv',pwd='123456')
或者
obj = models.UserInfo(user='yangmv',pwd='123456')
obj.save()
或者
dic = {'user':'yangmv','pwd':'123456'}
models.UserInfo.objects.create(**dic)
删
models.UserInfo.objects.filter(user='yangmv').delete()
改
models.UserInfo.objects.filter(user='yangmv').update(pwd='520')
或者
obj = models.UserInfo.objects.get(user='yangmv')
obj.pwd = '520'
obj.save()