04 Django模型基础
1. models字段类型
概述
django根据属性的类型确定以下信息
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的默认html控件
- 在管理站点最低限度的验证
django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后则django不会再生成默认的主键列
属性命名限制
遵循标识符规则
由于django的查询方式,不允许使用连续的下划线定义属性时,
需要字段类型,字段类型被定义在diango.db.models.fields目录下,为了方便使用被导入到django.db.models中
使用方式
- 导入from django.db import models
- 通过models.Field创建字段类型的对象,赋值给属性
逻辑删除和物理删除
对于重要数据都做逻辑删除,不做物理删除,实现方法是定义is_delete属性,类型为BooleanField,默认值为False
is_delete = models.BooleanField(default=False)
常用字段类型
AutoField
: 一个根据实际ID自动增长的IntegerField,通常不指定,如果不指定,主键字段id将自动添加到模型中
CharField
(max_length=字符长度)
- 字符串,默认的表单样式是 Input
TextField
大文本字段,一般超过4000使用,默认的表单控件是Textarea
IntegerField
- 整数
DecimalField(max_digits=None,decimal_places=None)
- 使用python的Decimal实例表示的十进制浮点数
- 参数说明
- DecimalField.max_digits -> 位数总数
- DecimalField.decimal_places -> 小数点后的数字位数
FloatField
: 用Python的float实例来表示的浮点数
BooleanField
- True/False 字段,此字段的默认表单控制是CheckboxInput
DateField([auto_now=False,auto_now_add=False])
- 使用Python的datetime.date实例表示的日期参数说明
- 参数说明
- DateField.auto_now
每次保存对象时,自动设置该字段为当前时间,用于**“最后一次修改”**的时间戳,它总是使用当前日期,默认为false- DateField.auto_now_add
当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用创建时的日期,默认为false- 注意:auto_now_add,auto_now,and_default 这些设置是相互排斥的他们之间的任何组合将会发生错误的结果
TimeField
: 使用Python的datetime.time实例表示的时间,参数同DateField
DateTimeField
: 使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
FileField
- 一个上传文件的字段
ImageField
:
- 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
- 需要安装Pillow: “pip install Pillow”
2. 常用字段参数
# 常用字段选项(通过字段选项,可以实现对字段的约束)
1. null=True
数据库中字段是否可以为空
2. blank=True
django的 Admin 中添加数据时是否可允许空值
一般null=True & blank=True 搭配着用,出现null=True就用上blank=True
3. primary_key = True
主键,对AutoField设置主键后,就会代替原来的自增id列
4. auto_now和auto_now_add
auto_now 自动创建 --- 无论添加或修改,都是当前操作的时间
auto_now_add 自动创建 --- 永远是创建时的时间
5. choices (后台admin下拉菜单)
USER_TYPE_LIST =(
(1,'超级用户'),
(2,'普通用户'),
)
user_type = models.IntegerField(choices=USER_TYPE_LIST,default=1,,verbose_name='用户类型')
6. max_length 最大长度
7. default 默认值
8. verbose_name Admin(后台显示的名称)中字段的显示名称
9. name|db_column 数据库中的字段名称
10. unique=True 不允许重复
11. db_index = True 数据库索引,例如:如果你想通过name查询的更快的话,给他设置为索引即可
12. editable=True 在Admin里是否可编辑,不可编辑则不显示
13. 设置表名
class Meta:
db_table ='person'
在创建模型迁移之时,经常会遇到以下问题,这是以为原先数据库中已经有数据,这时创建新的数据字段,原先的记录不知道填充什么内容进新增字段(假设不是所有新增字段都有默认值)
模型在admin后台默认的html控件
--> 渲染管理表单时使用的默认html控件
3.迁移怎么回滚
完成迁移之后,会在应用文件夹App/migrations
文件夹下创建迁移文件,并且在数据库表django_migrations
中创建对应记录
想要回滚,可以删除对应的迁移python文件以及对应数据库记录
4. models基本操作
一般的数据库操作流程:
- 创建数据库,设计表结构和字段
- 连接Mysql数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作
Django通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite,Django自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Django帮我们自动完成。
只要会写Model就可以了。django使用
对象关系映射(Object Relational Mapping,简称ORM)
框架去操控数据库。ORM(Object Relational Mapping)对象关系映射,是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
在Django模型中可以使用内部类Meta
为模型提供选项,具体请见文档
增删改查
ORM
- 模型 <=> 表
- 类结构 -> 表结构
- 对象 -> 表的一条数据
- 类属性 -> 表的字段
模型基本操作
-
增: (假设模型是Author)
- 创建对象实例,然后调用
save
方法
obj = Author() obj.first_name = "zhang" obj.last_name = 'san' obj.save()
- 创建对象并初始化,在调用save方法
obj = Author(first_name = "zhang",last_name = 'san') obj.save()
- 使用
create
方法
Author.objects.create(first_name = "zhang",last_name = 'san')
- 使用
get_or_create
方法,可以防止重复
Author.objects.get_or_create(first_name = "zhang",last_name = 'san')
- 创建对象实例,然后调用
注意: 添加失败是因为PersonModel模型中name属性设置的是unique
# 增加数据
def add_person(request):
# # 方式1
# try:
# p = PersonModel(name='张三', age=20)
# p.save()
# except Exception as e:
# print(e)
# return HttpResponse('添加失败')
# return HttpResponse('添加成功')
# 方式2
# PersonModel.objects.create(name='李四', age=25)
# return HttpResponse('添加成功')
# 方式3
ret = PersonModel.objects.get_or_create(name='李四', age=25)
print("ret",ret)
# ret:(<PersonModel:PersonModelobject(2)>,True)
# 如果是第一次创建: 则是True,如果已经存在则是False
return HttpResponse('添加成功')
-
删:
- 获取单个对象并调用
Queryset的delete()方法
p = PersonModel.objects.first() # 获取第一个数据 p.delete() p = PersonModel.objects.get(name="李四") # 根据对应的id获取数据 p.delete()
注意: objects不能直接调用delete()方法
- 使用模型过滤
filter()
,再对过滤结果进行删除
# 使用过滤器 PersonModel.objects.filter(age__gt = 15).delete() # 删除年龄大于15的数据
- 获取单个对象并调用
-
改:
- 直接使用
对象.属性
修改
# 获取数据 p = PersonModel.objects.first() p.age = 25 p.save() # 修改多条数据 p_list = PersonModel.objects.all() for p in p_list: p.age = 25 p.save()
- 修改多条数据
PersonModel.objects.all().update(age=25) # 修改所有数据
save()
更新时,会对所有字段进行更新操作,如果想要只更新某个字段,减少数据库操作,可以这么做:obj.first_name = "zhang" obj.save(update_fields = ['first_name'])
- 直接使用
-
查:
对查询集可使用的函数
-
get()
:获取单条数据Author.objects.get(id=123)
- 如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常
- 如果找到多个,会引发模型类.MultipleObjectsReturned异常
-
first()
:返回査询集(Queryset)
中的第一个对象 -
last()
:返回查询集中的最后一个对象 -
count()
:返回当前查询集中的对象个数 -
exists()
:判断查询集中是否有数据,如果有数据返回True没有反之 -
all()
获取全部数据: Author.objects.all() -
values()
:获取指定列的值,可以传多个参数! 返回包含字典的列表(保存了字段名和对应的值) —>Author.objects.all().values(‘password’)
-
values_list()
:获取指定列的值,可以传多个参数! 返回包含元组列表(只保存值) —>Author.objects.all().values_list(‘password’)
-
filter()
查询集可以被链式调用,Author.objects.filter(name="seven").filter(age=18)
进阶操作
# 获取个数
Author.objects.filter(name="seven").count()
# 获取id大于1的值
Author.objects.filter(id__gt=1) # SELET * FROM Author WHERE id > 1
# 获取id大于或等于1的值
Author.objects.filter(id__gte=1) # SELET * FROM Author WHERE id >= 1
# 获取id小于10的值
Author.objects.filter(id__lt=10) # SELET * FROM Author WHERE id < 10
# 获取id小于或等于10的值
Author.objects.filter(id__lte=10) # SELET * FROM Author WHERE id >= 1
# 获取id大于1且小于10的值
Author.objects.filter(id__lt=10,id__gt=1) # SELET * FROM Author WHERE id > 1 AND id < 10
# 获取id在11,22,33的数据
Author.objects.filter(id__in=[11,22,33]) # SELET * FROM Author WHERE id IN (11,22,33)
# 获取id`不在`11,22,33的数据
Author.objects.exclude(id__in=[11,22,33]) # SELET * FROM Author WHERE id NOT IN (11,22,33)
# 获取name包含"ven"的数据 (和数据库中like语法相似)
Author.objects.filter(name__contains="ven") # SELET * FROM Author WHERE name LIKE '%ven%'
# icontains()大小写不敏感
Author.objects.filter(name__icontains="ven")
Author.objects.filter(name_regex="^ven") # 正则匹配
Author.objects.filter(name_iregex="^ven") # 正则匹配,忽略大小写
Author.objects.filter(age_range=[10,20]) # 范围bettwen and
# startswith,istartswith,endswith,iendswith:
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的, 其实不带i的也忽略大小写
Author.objects.filter(name='seven').order_by('id','age') # asc升序, 多个属性->id相同时,按照age来排序
Author.objects.filter(name='seven').order_by('-id') # desc降序
Author.objects.all()[18:20] # 切片,取所有数据的18条到20条,分页的时候用的到
# 下标从0开始,不能为负数,可以实现分页
# 手动分页
page 页码
per_page 每页数量 = 5
第1页(page=1): 0-4 =>[0:5]
第2页(page=2): 5-9 =>[5:10]
第3页(page=3): 10-14 =>[10:15]
第4页(page=4): 15-19 =>[15:20]
每一页数据范围:[(page-1) * per_page : page * per_page]
# 聚合
使用aggregate()函数返回聚合函数的值
- Avg:平均值
- Count:数量
- Max:最大
- Min:最小
- Sum:求和
from django.db.models import Count,Min,Max,Sum
Author.objects.aggregate(Max('age'))
5. views.py
from django.http import HttpResponse
from django.shortcuts import render
from django.db.models import Avg, Max, Min, Sum
# Create your views here.
from App.models import *
# 增加数据
def add_person(request):
# # 方式1
# try:
# p = PersonModel(name='张三', age=20)
# p.save()
# except Exception as e:
# print(e)
# return HttpResponse('添加失败')
for i in range(10):
p = PersonModel(name='张三'+str(i), age=20+i)
p.save()
# return HttpResponse('添加成功')
# 方式2
# PersonModel.objects.create(name='李四', age=25)
# return HttpResponse('添加成功')
# 方式3
# ret = PersonModel.objects.get_or_create(name='李四', age=26)
# print("ret",ret)
# ret:(<PersonModel:PersonModelobject(5)>,True)
# 如果是第一次创建: 则是True,如果已经存在则是False
return HttpResponse('添加成功')
# 删除数据
def del_person(request):
try:
# p = PersonModel.objects.first() # 获取第一个数据
# p = PersonModel.objects.get(name="李四") # 根据对应的id获取数据
# p.delete()
# 使用过滤器
PersonModel.objects.filter(age__gt = 15).delete() # 删除年龄大于15的数据
except Exception as e:
print(e)
return HttpResponse('删除失败')
return HttpResponse('删除成功')
# 修改数据
def update_person(request):
try:
# 获取数据
# p = PersonModel.objects.first()
# p.age = 25
# p.save()
# 修改多条数据
p_list = PersonModel.objects.all()
# PersonModel.objects.all().update(age=25) # 修改所有数据
for p in p_list:
p.age = 25
p.save()
except Exception as e:
print(e)
return HttpResponse('修改失败')
return HttpResponse('修改成功')
def get_person(response):
# get() 方法获取单个数据
# p = PersonModel.objects.get(id=1)
# p = PersonModel.objects.get(pk=18) # primary key等于18
# p = PersonModel.objects.get(age=100) # 找不到对应的数据时会报错,找到多条数据时也会报错
# print(p,type(p)) # <PersonModel: PersonModelobject(1)> <class 'App.models.PersonModel'>
# print(p.name,p.age)
# all() 方法返回所有数据
p_list = PersonModel.objects.all()
print(p_list,type(p_list)) # <PersonModel: PersonModel object (25)>]> <class 'django.db.models.query.QuerySet'> 查询集,可以遍历
# first() 方法获取第一个数据
# p = PersonModel.objects.first()
# last() 方法获取最后一个数据
# p = PersonModel.objects.last()
# exists() 方法判断数据是否存在
# if PersonModel.objects.filter(name='张三').exists():
# print('存在')
# else:
# print('不存在')
# values() 方法返回指定字段的数据
# p_list = PersonModel.objects.values('name','age') #返回包含字典的列表
p_list = PersonModel.objects.values_list('name','age') # 返回包含元组列表
print(p_list,type(p_list))
# filter() 方法过滤数据,返回一个```查询集````,参数为空时返回所有数据
# p_list = PersonModel.objects.filter(age__gt=15) # 年龄大于15的数据
# p_list = PersonModel.objects.filter(name__contains='三') # 名字包含'三'的数据
# p_list = PersonModel.objects.filter(name__startswith='张') # 名字以'张'开头的数据
# exclude() 方法排除数据,返回一个```查询集````,参数为空时返回所有数据
# p_list = PersonModel.objects.exclude(age__gt=15) # 年龄不大于15的数据
# order_by() 方法排序数据,返回一个```查询集````,参数为空时返回所有数据
# p_list = PersonModel.objects.order_by('age') # 按年龄排序
# p_list = PersonModel.objects.order_by('-age') # 按年龄倒序排序
# contains() 方法查找字符串是否在指定字段中,返回一个```查询集````,参数为空时返回所有数据
p_list = PersonModel.objects.filter(name__contains='三') # 名字包含'三'的数据
print(p_list,type(p_list))
# regex() 方法查找正则表达式是否匹配指定字段,返回一个```查询集````,参数为空时返回所有数据
# p_list = PersonModel.objects.filter(name__regex=r'^张') # 名字以'张'开头的数据
# 聚合函数
# count() 方法计算数据条数
# count = PersonModel.objects.count()
# print(count)
# max() 方法获取最大值
# max_age = PersonModel.objects.all().aggregate(Max('age'))
# print(max_age)
# min() 方法获取最小值
# min_age = PersonModel.objects.all().aggregate(Min('age'))
# print(min_age)
# sum() 方法求和
# total_age = PersonModel.objects.all().aggregate(Sum('age'))
# print(total_age)
# avg() 方法求平均值
result = PersonModel.objects.all().aggregate(Avg('age'))
print(result)
return HttpResponse('获取成功')
# 分页数据
def paginate(request,page=1):
# 页码: page
# 每页显示条数: per_page
per_page = 10
# 数据范围的计算公式 -> (页码-1)*每页显示条数 ~ 页码*每页显示条数
all = PersonModel.objects.all()
start = (page-1) * per_page
end = page * per_page
p_list = all[start:end]
return render(request,"page_list.html",{'p_list':p_list})
# 自动分页器
def auto_paginate(request):
# 自动分页器
from django.core.paginator import Paginator
# 实例化分页器
paginator = Paginator(PersonModel.objects.all(), 10)
page = 1
persons = paginator.page(page) # 获取第page页的数据
paginator.page_range # 页码范围,可以遍历