Python后台开发基础--模型类实现
1 ORM原理与数据库配置
1.1 模块安装
代码部分:
pip install pymysql pip install mysqlclient
1.2 模块安装常见问题
- time out 超时解决方案: pip install 包名 --user-i https://pypi.tuna.tsinghua.edu.cn/simple
- 缺少c ++ 插件解决方案:https://www.jb51.net/article/151033.htm
1.3 Pycharm连接 Mysql
- 保证pycharm是专业版.
- 创建mysql连接.
- 测试连接,当出现successful时,说明连接信息无误,可以正常使用pycharm操作mysql数据库.
- 连接数据库可能遇到的问题:
pymysql.err.OperationalError: (1045, "Access denied for user'root'\@'localhost' (using password: YES/NO)")
- 解决方案: 检查Pycharm使用的账号密码,与cmd下登录Mysql数据库的账号密码是否一致.
unrecognized or represents more than one time zone. You must configureeither the server or JDBC driver (via the serverTimezone configurationproperty) to use a more specifc time zone value if you want to utilize timezone support. 时区错误
- 解决方案:
- cmd下 执行mysql_upgrade -uroot -p --force
- 重启mysql服务
- 进入mysql(mysql -u root -p)
- set global time_zone = ‘+8:00’;
- flush privileges ;
- show variables like ‘’%time_zone%’’ ;
1.4 Pycharm—数据库创建
创建命令如下:
create database [数据库名] charset=’utf8’;
注:
- 使用pycharm创建数据库的时候一定要注意: 声明utf8字符集
- 选中需要执行的sql语句,使用 ctrl+enter执行该语句.
1.5 ORM框架原理
- django中内嵌了ORM框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。
- ORM在项目与数据库之间起桥梁作用,使用PyMySQL和mysqlclient连接Mysql数据库的接口。
- 在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。例如:模型类BookInfo–映射到–> 数据表bookinfo。使数据库设计更加简单
- ORM框架可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程,也就是我们下边提到的数据库迁移操作.
- 用面向对象的方式去操作数据库的创建表、增加、修改、删除、查询等操作。把面向对象中的类和数据库表一一对应,通过操作类和对象,对数据表实现数据操作,不需要写sql,由orm框架生成。
- Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite…,如果数据库迁移,只需要更换Django的数据库引擎即可
1.6 数据库信息配置
- 默认情况下,配置使用SQLite。若不使用SQLite作为数据库,则需要额外的设置
- 其中ENGINE设置为数据库后端使用。内置数据库后端有:
'django.db.backends.postgresql'
'django.db.backends.mysql'
'django.db.backends.sqlite3'
'django.db.backends.oracle'
注:在实际的开发项目中,多数情况下使用的是Mysql数据库引擎.
- Mysql数据库引擎的配置:
在主路由的settings.py文件中, 通过DATABASES项进行数据库设置
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydemo',
'USER': 'root',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '3306', } }
- 数据库连接字段说明:
字段 | 说明 |
---|---|
NAME | 使用得数据库数据库名称 |
USER | 数据库登录用的账户 |
PASSWORD | 数据库登录用的密码 |
HOST | 数据库服务器的位置,我们一般数据库服务器和客户端都是在一台主机上面,所以一般默认都填127.0.0.1或者localhost |
PORT | 数据库启动的端口号 |
字段 | 说明 |
NAME | 使用得数据库数据库名称 |
USER | 数据库登录用的账户 |
- start—数据库信息快捷键的配置
- 打开pycharm的设置文件
- 跳转到快捷键配置界面
注: 搜索框搜索 live —> 点击Python的小箭头 --点击+号 —选择live template
- 配置快捷键信息
注: 配置完成,点击OK ,在settings中使用start进行测试使用.
2 Model模型层
2.1 Model 概述
- 在Django中model是你数据的单一、明确的信息来源。它包含了你存储的数据的重要字段和行为。通常,一个模型类(model)映射到一个数据库表。
- 定义简介:
- 每个模型都是一个python类,它是django.db.models.Model的子类
- 模型的每个属性都代表一个数据库字段
- 综上所述,Django为您提供了一个自动生成的数据库访问API,详细见官方文档。
- model与数据库结构对应关系图如下:
2.2 快速入门
下面举类详细分析model如何创建类,及各个语法的意义,如定义一个Person模型,包含两个属性first_name和last_name.
from django.db import models class Person(models.Model):
#每个类都必须继承models.Model
first_name = models.CharField(max_length=30)
#数据库中的列
last_name = models.CharField(max_length=30)
#数据库中的列
def Meta(self):
db_table = 'person'
# 自定义创建的表名是person,不指定默认表名:myapp_person
first_name 和last_name是模型的字段,每个字段被指定为一个类属性,每个属性映射到一个数据库表的列。
上面的Person模型将会如下面sql语句在数据库中创建一个表:
create table myapp_person(
'id':serial not null primary key,
'first_name' varchar(30) not null,
'last_name' varchar(30) not null, );
2.3 常用字段
字段 | 说明 |
---|---|
AutoField | 1.自增列 = int(11) 2.如果没有的话,django 自动创建一个自增的id 列 3.如果要显式的自定义一个自增列,必须设置primary_key=True。 4.一个model类不能有两个自增的AutoField |
CharField | 1.字符串字段 2.必须设置max_length参数 3.如果超过254个字符,建议使用TextField。 |
BooleanField | 1.布尔类型=tinyint(1) 2.不能为空,可添加Blank=True |
ComaSeparatedIntegerField | 1.用逗号分割的数字=varchar 2.继承CharField,所以必须 max_lenght 参数 |
ComaSeparatedIntegerField | 1. 用逗号分割的数字=varchar 2. 继承CharField,所以必须 max_lenght 参数 |
DateField | 1.日期类型 date 2.DateField.auto_now:保存时自动设置该字段为现在日期,最后修改日期 3.DateField.auto_now_add:当该对象第一次被创建是自动设置该字段为现在日期,创建日期。 |
DateTimeField | 1.日期时间类型 datetime 2.同DateField的参数 |
Decimal | 1.十进制小数类型 = decimal 2.DecimalField.max_digits:数字中允许的最大位数 3.DecimalField.decimal_places:存储的十进制位数 例如,要存储的数字最大长度为3位,而带有两个小数位,可以使用: models.DecimalField( max_digits=3, decimal_places=2,) |
EmailField | 一个带有检查 Email 合法性的 CharField |
FloatField | 浮点类型 = double |
IntegerField | 整形 |
BigIntegerField | 长整形 |
GenericIPAddressField | 一个带有检查 IP地址合法性的 CharField,存储IP地址 |
NullBooleanField | 允许为空的布尔类型 |
PositiveIntegerFiel | 正整数 |
PositiveSmallIntegerField | 正smallInteger |
SlugField | 存储 减号、下划线、字母、数字 |
SmallIntegerField | 1.数字 2.数据库中的字段有:tinyint、smallint、int、bigint |
TextField | 大文本。默认对应的form标签是textarea |
TimeField | 时间 HH:MM[:ss[.uuuuuu]] |
URLField | 一个带有URL合法性校验的CharField |
BinaryField | 1.二进制 2.存储二进制数据。不能使用filter函数获得QuerySet。 |
ImageField | 1.图片 2.ImageField.height_field、ImageField.width_field:如果提供这两个参数,则图片将按提供的高度和宽度规格保存。 3.该字段要求 Python Imaging 库Pillow。 4.会检查上传的对象是否是一个合法图片。 |
FileField | 1.FileField.upload_to:一个用于保存上传文件的本地文件系统路径,该路径由 MEDIA_ROOT 中设置 2.这个字段不能设置primary_key和unique选项.在数据库中存储类型是varchar,默认最大长度为100 |
FilePathFiel | 1.FilePathField.path:文件的绝对路径,必填 2.FilePathField.match:用于过滤路径下文件名的正则表达式,该表达式将用在文件名上(不包括路径)。 3.FilePathField.recursive:True 或 False,默认为 False,指定是否应包括所有子目录的路径。例如:FilePathField(path="/home/images", match=“foo.*”, recursive=True) 将匹配“/home/images/foo.gif”但不匹配“/home/images/foo/bar.gif” |
2.4 常用字段约束
字段 | 说明 |
---|---|
null | 如果是True,Django会在数据库中将此字段的值置为NULL,默认值是False |
blank | 1.如果为True时django的 Admin 中添加数据时可允许空值,可以不填。如果为False则必须填。默认是False。 2.null纯粹是与数据库有关系的。而blank是与页面必填项验证有关的 |
primary_key= False | 主键,对AutoField设置主键后,就会代替原来的自增 id 列 |
auto_now auto_now_add | 1.auto_now 自动创建—无论添加或修改,都是当前操作的时间 2.auto_now_add 自动创建—永远是创建时的时间 |
choices | 1.一个二维的元组被用作choices,如果这样定义,Django会select box代替普通的文本框, 2.并且限定choices的值是元组中的值 |
max_length | 字段长度 |
default | 默认值 |
verbose_name | Admin中字段的显示名称,如果不设置该参数时,则与属性名 |
db_column | 数据库中的字段名称 |
unique=True | 不允许重复 |
db_index = True | 数据库索引 |
editable=True | 在Admin里是否可编辑 |
error_messages=None | 错误提示 |
auto_created=False | 自动创建 |
help_text | 在Admin中提示帮助信息 |
validators=[] | 验证器 |
upload-to | 文件上传时的保存上传文件的目录 |
2.5 数据库迁移
2.5.1 概念
对于django而言,强大之处就在于在通过迁移命令执行迁移后,会根据model.py文件定义的类字段生成对应的sql语句脚本,进行相应的数据库操作。
2.5.2 迁移命令
- 对整个项目进行迁移
# 生成迁移文件
python manage.py makemigrations
#执行迁移
python manage.py migrate
- 对单个app进行迁移
# 生成迁移文件
python manage.py makemigrations [模块名]
#执行迁移
python manage.py migrate [模块名]
注:
- 执行迁移前,核对数据库的连接信息,账号密码的核对,数据库是否存在.
- 修改模型类后,若需要数据库同步修改的内容,则需要重新进行迁移步骤,才可以完成字段的同步
- 写好模型类后,在Pycharm的terminal 命令行进行数据的迁移和维护
2.6 模型类的增删改查
2.6.1 定义模型类
class User(models.Model):
username = models.CharField(max_length= 16,unique= True )
password = models.CharField(max_length= 16,default= "123456")
gender = models.PositiveSmallIntegerField(default= 0)
age = models.IntegerField(null= True )
createDatetime = models.DateTimeField( auto_now_add= datetime.datetime.now())
注: terminal 命令行
– python manage.py makemigrations
– python manage.py migrate
2.6.2 进入shell交互式编程
- 在pycharm中的Terminal中输入python manage.py shell,进入交互式编程
- 导入user中的模型类: from user.models import *
2.6.3 增加数据
2.6.3.1 create方法
user = User.objects.create( username = "name2", )
#等价于
user = User(username="name2")
user.save()
2.6.3.2 模型对象.save() -推荐使用
user = User()
user.username = 'name1'
user.id
user.save()
注: 调用save方法后user对象封装写入数据库中的数据内容
2.6.4 删除数据
delete方法:
#第一种 根据id直接删除
user.delete()
#先查询后删除,删除的是查询后的对象
User.objects.filter(id=2).delete()
2.6.5 修改数据
2.6.5.1 save()
#修改user用户的密码为pass1
user.password = 'pass1' user.save()
注:若模型类中修改的id存在,则为修改数据,不存在,为新增数据
2.6.5.2 update()
User.objects.filter(【条件】).update(属性=属性值) 例如: User.objects.filter(id=2).update(password="pass2")
2.6.6 查询数据
2.6.6.1 查询语法格式
- 语法: 【模型类名】.objects.【方法】(【条件】)
- 常用方法
方法 | 说明 |
---|---|
get() | 返回满足条件的单条数据 |
count() | 返回查询集中的数据个数 |
first() | 取第一个值 |
last() | 取最后一个值 |
exists() | 判断是否存在 |
all() | 返回所有数据 |
filter(条件) | 返回符合条件的数据 |
exclude(条件) | 返回不符合条件的数据 |
values() | 返回字典列表 |
order_by() | 排序查询. 默认为升序排列,降序可在字段前加一个负号 |
注:
- get属于单条查询方法,当查询数据不存在时会引发异常(DoesNotExist),查询到多个数据时也会引发异常(MultipleObjectsReturned)
- all,filter,exclude.values,order_by属于多条查询方法
- 从数据库中获取对象的集合(Queryset)。
- 查询集可以用过滤器筛选对象(filter(条件)),可以多次调用。
- 过滤器实际就是一个函数
- 过滤器产生新的查询集
- 查询集就是一个Queryset的列表
- 查询集是不会访问数据库的,直到访问数据时才访问数据库。如迭代、序列化、与if合用等
2.6.6.2 比较查询
- 语法: 【字段名】__【条件关键字】=【比较值】
- 条件参数:
条件 | 说明 |
---|---|
相等 | exact |
大于 | gt |
大于等于 | gte |
小于 | lt |
小于等于 | lte |
为空查询 | isnull |
- 实例:
#查询id\>=2的所有用户
users = User.objects.filter(id__gte=2)
2.6.6.3 模糊查询
- 条件参数
条件 | 说明 |
---|---|
包含 | contains |
开头 | startswith |
结尾 | endswith |
- 实例:
# 查询用户名中包含'1'的用户
user1_s = User.objects.filter(username__contains='1')
# 查询用户名以'name1'开头的用户
user2_s = User.objects.filter(username__startswith='name1')
# 查询邮箱以@qq.com'结尾的用户
user3_s = User.objects.filter(email__endswith='@qq.com')
2.6.6.4 范围查询
- 条件参数
条件 | 说明 |
---|---|
范围 | in |
- 实例:
#查询username属于["name1","name2"]的user对象
users = User.objects.filter(username__in= ["name1","name2"]
- 导入方式: from django.db.models import F
- F对象的应用场景: 多数用于同行数据字段间的互相比较
- 代码实例:
# 可以使用模型的字段A与字段B进行比较,如果A写在了等号的左边,则B出现在等号的右边,需要通过F对象构造
list.filter(bread__gte=F('b_commet')) # django支持对F()对象使用算数运算
list.filter(bread__gte=F('b_commet') * 2)
- F()对象中还可以写作“模型类__列名”进行关联查询list.filter(isDelete=F(‘heroinfo__isDelete’))
#对于date/time字段,可与timedelta()进行运算
list.filter(bpub_date__lt=F('b_pub_date') + timedelta(days=1))
2.6.6.6 Q对象
- 导入方式: from django.db.models import Q
- Q对象的应用场景: 多数用于字段间的逻辑比较
- 代码实例:
#过滤器的方法中关键字参数查询,会合并为And进行
#需要进行or查询,使用Q()对象
#Q对象(django.db.models.Q)用于封装一组关键字参数,这些关键字参数与“比较运算符”中的相同
from django.db.models import Q list.filter(Q(pk__lt=6))
#Q对象可以使用&(and)、|(or)操作符组合起来
#当操作符应用在两个Q对象时,会产生一个新的Q对象
list.filter(pk__lt=6).filter(b_commet__gt=10)
list.filter(Q(pk__lt=6)|Q(b_commet__gt=10))
#使用~(not)操作符在Q对象前表示取反
list.filter(~Q(pk__lt=6))
#可以使用&|~结合括号进行分组,构造做生意复杂的Q对象
#过滤器函数可以传递一个或多个Q对象作为位置参数,如果有多个Q对象,这些参数的逻辑为and #过滤器函数可以混合使用Q对象和关键字参数,所有参数都将and在一起,Q对象必须位于关键字参数的前面
2.7 懒加载
2.7.1 原理
- 存在于外键和多对多关系
- 不检索关联对象的数据
- 调用关联对象会再次查询数据库
- 执行res = models.Article.objects.all()这样的类似查询时,并没有真正去数据库操作取出、生成数据,而是生成Query_set迭代对象,当使用到模型类的数据时,才向数据库加载数据的具体内容
- 每次查询回来数据,Django就会把这些数据保存在cache中,当你下次使用时,不会去数据库再次查询,而是去cache里面取,即减少了数据库的压力,又节省了内存.
2.7.2 实例
users = User.objects.all()
for user in users:
print(user.username)
2.8 链式调用
2.8.1 原理
在使用QuerySet进行查找操作的时候,可以提供多种操作。比如过滤完后还要根据某个字段进行排序,那么这一系列的操作我们可以通过一个非常流畅的链式调用的方式进行。
2.8.2 QuerySet方法参数
QuerySet方法 | 返回类型 | 说明 |
---|---|---|
get() | 模型对象 | 满足条件的唯一对象 |
all() | QuerySet | 所有对象 |
filter() | QuerySet | 满足条件的对象 |
exclude() | QuerySet | 不满足条件的对象 |
order_by() | QuerySet | 排序 |
count() | int | 结果的数量 |
exists() | boolean | 结果是否存在 |
2.8.3 代码实例
#从文章表中获取标题为123,并且提取后要将结果根据发布的时间进行排序
articles=Article.objects.filter(title='123').order_by('create_time')
注: 可以看到order_by方法是直接在filter执行后调用的。这说明filter返回的对象是一个拥有order_by方法的对象。而这个对象正是一个新的QuerySet对象。因此可以使用order_by方法。
排序语法格式: order_by(【字段1】,-【字段2】)
#先根据字段1升序排列,如果字段1相同,则根据字段2降序排列 例如:
user_s = User.objects.all().order_by('createDatetime','-birthday')