一、ORM框架
Django对各种数据库提供了很好的支持,包括PostgreSQL、MySQL、SQLite和Oracle,且为这些数据库提供了统一API方法,这些API统称为ORM框架。
通过Django内置的ORM框架可以实现数据库连接和读写操作。
二、模型定义与数据迁移
ORM框架是一种程序技术,用于实现 面向对象编程语言中不同类型系统的数据之间的转换,从效果上说,它创建了一个可在编程语言中使用的“虚拟对象数据库”,通过对虚拟对象数据库的操作,实现对目标数据库的操作,虚拟对象数据库与目标数据库是相互对应的。在Django中虚拟对象数据库也称为模型。模型字段如下:
- AutoField: 自增长类型,数据表的字段类型为整数,长度为11位
- BigAutoField: 自增长类型,数据表的字段类型为bigint,长度为20位
- CharField: 字符类型
- BooleanField: 布尔类型
- CommonSeparateIntegerField: 用逗号分割的整数类型
- DateField: 日期(Date)类型
- DatetimeField: 日期时间(Datetime)类型
- Decimal: 十进制小数类型
- EmailField: 字符类型,存储邮箱格式的字符串
- FloatField: 浮点数类型,数据表的字段类型变成Double类型
- IntegerField: 整数类型,数据表的字段类型为11位的整数
- BigIntegerField: 长整数类型
- IPAddressField: 字符类型,存储Ipv4地址的字符串
- GenericIPAddressField: 字符类型,存储Ipv4和Ipv6地址的字符串
- NullBooleanField: 允许为空的布尔类型
- PositiveIntegerField: 正整数的整数类型
- PositiveSmallIntegerField: 小正整数类型,取值范围0~32767
- SlugField: 字符类型,包含字母、数字、下划线和连字符的字符串
- TextField: 长文本类型
- TimeField: 时间类型,显示时分秒HH:MM[:ss[.uuuuuuu]]
- URLField: 字符类型,存储路由格式的字符串
- BinaryField: 二进制数据类型
- FileField: 字符类型,存储文件路径的字符串
- ImageField: 字符类型,存储图片路径的字符串
- FilePathField: 字符类型,从特定的文件目录选择某个文件
允许设置的参数
源码Field(django/db/models/fields/init.py)
- verbose_name: 默认None,在Admin站点管理设置字符的显示名称
- primary_key: 默认为False,若为True,则将字段设置成主键
- max_length: 默认为None,设置字段的最大长度
- unique: 默认为False,若为True,则设置字段的唯一属性
- blank: 默认为False, 若为True,则设置字段允许为空值,数据库将存储空字符串
- null: 默认为False,若为True,则字段允许为空值,数据库表现为NULL
- db_index: 默认为False,若为True,则以此字段来创建数据库索引
- default: 默认为NOT_PROVIDEDD对象,设置字段的默认值
- editable: 默认为True,允许字段可编辑,用于设置Admin的新增数据的字段
- serialize: 默认为True,允许字段序列化,可将数据转化为JSON格式
- unique_for_date: 默认为None,设置日期字段的唯一性
- unique_for_month: 默认为None,设置月份字段的唯一性
- unique_for_year: 默认为None,设置年份字段的唯一性
- choices: 默认空列表,设置字段的可选值
- help_text: 默认为空字符串,用于设置表单的提示信息
- db_column: 默认为None,设置数据表的列名称,若不设置,则字段名作为列名
- db_tablespace: 默认为None,如果字段已创建索引,那么数据库的表空间名称将作为该字段的索引名称。注意:部分数据库不支持表空间
- auto_created: 默认为False,若为True,则自动创建字段,用于一对一的关系模型
- validators: 默认为空列表,设置字段内容的验证函数
- error_message: 默认为None,设置错误提示
- 以上参数适用于所有字段
- 以下适用于Meta
- abstract: 若设置为True,则该模型为抽象模型,不会在数据库里创建数据表
- app_label:属性值为字符串,将模型设置为指定的项目应用,比如将index的models.py定义的模型A指定到其他的APP里
- db_table: 属性值为字符串,设置模型所使用的数据库的表名
- db_tablespace: 属性值为字符串,设置模型所使用的数据库的表名
- get_lastest_by: 属性值为字符串或列表,设置模型数据的排序方式
- managed: 默认为True,支持Django命令执行数据迁移;若为False,则不支持数据迁移功能
- order_with_respect_to: 属性值为字符串,用于多对多的模型关系,指向某个关系模型的名称,并且模型名称必须为英文小写。若A模型对B模型一对多,两个模型关联后,当查询模型A的某条数据时,可使用get_b_order()和set_b_order()来获取B的关联数据;可使用get_next_in_order()和get_previous_in_order()获取当前数据的上一条和下一条数据
- ordering: 属性值为列表,将模型数据以某个字段进行排序
- permissions: 属性值为元组,设置模型的访问权限,默认设置添加、修改和删除的权限
- proxy:若设置为True,则为模型创建代理模型,即为模块A克隆一个相同的模型B
- required_db_features:属性值为列表,声明模型依赖的数据库功能,如['gis_enabled'],表示模型依赖GIS功能
- required_db_vendor: 属性值为列表,声明模型依赖的数据库,默认支持SQLite、PostgreSQL、MySQL和Oracle
- select_on_save: 数据新增修改算法,通常无需设置,默认为False
- indexes: 属性值为列表,定义数据库表的索引列表
- verbos_name: 属性值为字符串,设置模型直观可读的名称并以复数形式表示
- verbos_name_plural: 与verbos_name相同,以单数形式表示
- label: 只读属性,属性值为app_label.object_name
- label_lower: 与label相同,但其值为字母小写
导数据
# 导出项目所有数据表 python manage.py dumpdata > data.json # 导出某个项目名称所有模型 python manage.py dumpdata index > data.json # 导出某个项目某个模型名称 python manage.py dumpdata index.PersonInfo > data.json # 导入数据 python manage.py loaddata data.json
三、数据表关系
# OneToOneField、ForeignKey、ManyToManyField # 参数 - to: 必选参数,关联的模型名称 - on_delete: 必选参数,设置数据删除模式,删除模型包括:CASCADE/PROTECT/SET_NULL/SET_DEFAULT/SET/DO_NOTHING - limit_choices_to: 设置外键的下拉选项,用于模型与表单和Admin后台系统 - related_name: 用于模型之间的关联查询,如反向查询 - related_query_name: 设置模型的查询名称,用于filter或get查询,若设置参数related_name则以该参数为默认值,若没有设置,则以模型名称的小写为默认值 - to_field: 设置外键与其他模型字段的关联性,默认关联主键,若要关联其他字段,则该字段必须具有唯一性 - db_constraint: 在数据库里是否创建外键约束,默认为true - swappable: 设置关联模型的替换功能,默认为true,比如模型A关联模型B,想让模型C继承并替换B使得A与模型C之间关联 - symmetrical: 仅限于ManyToManyField,设置多对多字段之间的对称模式 - through: 仅限于ManyToManyField,设置自定义模型C,用于管理和创建模型A和B否多对多关系 - through_fields: 仅限于ManyToManyField,设置模型C的字段,确认模型C的哪些字段用于管理A和B否多对多关系 - db_table: 仅限于ManyToManyField,为管理和存储多对多关系的数据表设置表名称
四、数据查询
去重distinct
# 去重查询,distinct无需设置参数,去重方式根据values设置的字段执行 # SQL: select * from index_vocation where job='123'; v = Vocation.objects.values('job').filter(job='123').distinct()
聚合查询annotate、aggregate
# annotate类似sql里面的group by # 如果不设置values,默认对主键进行group by分组 # SQL: select job, sum(id) as 'id__sum' from index_vocation group by job; v = Vocation.objects.annotate(Sum('id')) # aggregate是计算某个字段的值并返回计算结果 # SQL: select count(id) as 'id__count' from index_vocation v = Vocation.objects.aggregate(id_count=Count('id'))
结果集union、intersection、difference
# 每次查询的字段必须一致 v1 = Vocation.objects.filter(payment__gt=9000) v2 = Vocation.objects.filter(payment__gt=5000) # 使用SQL UNION来组合两个或多个查询结果的并集 v1.union(v2) # 使用SQL INTERSECT来获取两个或多个查询结果的交集 v1.intersection(v2) # 使用SQL EXCEPT来获取两个或多个查询结果的差集 v2.difference(v2)
查询条件get:查询字段必须是主键或者唯一约束的字段,且查询的数据必须存在,否则程序会抛异常
查询条件filter:查询字段没有限制,只要该字段是数据表某一字即可。查询结果以列表形式返回,查询结果为空就返回空列表
多表查询select_related、prefetch_related
# select_related参数为字符串格式(外键字段related_name), 使用left outer join方式查询两个数据表 # 查询模型PersonInfo的name字段和模型Vocation的payment字段 p = PersonInfo.objects.select_related('personinfo').values('name', 'personinfo__payment') # select_related使用SQL的join实现的,对于多对多会增加数据查询时间和内存占用;prefetch_related更有优势 # 查询模型Program的某行数据 p = Program.objects.prefetch_related('performer').filter(name='123').first() # 根据外键字段proformer获取当前数据的多对多或一对多关系 p.performer.all()
执行sql
# extra: 结果集修改器,一种提供额外查询参数的机制 # 查询job=123的数据 v = Vocation.objects.extra(where=['job=%s'], params=['123']) # 新增查询字段seat, select_params为selec的%s提供参数 v = Vocation.objects.extra(select={'seat': '%s'}, select_params=['seatInfo']) # raw v = Vocation.objects.raw('select * from index_vocation') v[0] # execute很容易受到sql注入攻击 from django.db import connection cursor = connection.cursor() cursor.execute('select * from index_vocation') # 读取第一行数据 cursor.fetchone() # 读取所有数据 cursor.fetchall()
迁移到不同数据库
# 在default数据库中创建数据表 python manage.py migrate # 在db1中创建数据表 python manage.py migrate --database=db1
五、数据库事务
事物是指作为单个逻辑执行的一系列操作,这些操作具有原子性,即这些操作要么完全执行,要么完全不执行。 事物处理可以确保事务性单元内所有操作都成功完成,否则不会执行数据操作。 事物四大特性ACID: - 原子性(Atomicity):一个事物是一个不可分割的工作单位,事物中包括的操作要么都做,要么都不做。 - 一致性(Consistency):事物必须使数据库从某个一致性状态到另一个一致性状态,一致性与原子性是密切相关的。 - 隔离性:一个事物的执行不能被其他事物干扰,即一个事物内部的操作及使用的数据对其他事物是隔离的,各个事物之间互不干扰。 - 持久性:也称永久性(Permanence),指一个事物一旦提交,它对数据库中数据的改变应该是永久性的,其他操作或故障不应该对其有任何影响。 # Django事物定义在django/db/transaction.py - atomic(): 在视图函数或视图类使用事物 - savepoint(): 开启事物 - savepoint_rollback(): 回滚事物 - savepoint_save(): 提交事物
from django.shortcuts import render from .models import * from django.db import transaction from django.db.models import F @transaction.atomic def index(request): # 开启事物保护 sid = transaction.savepoint() try: id = request.GET.get('id', '') if id: v = Vocation.objects.filter(id=id) v.update(payment=F('payment') + 1) print('Done') # 提交事物 # 如不设置,当程序执行完成后,会自动提交事物 # transaction.savepoint_commit(sid) else: # 全表的payment字段自减1 Vocation.objects.update(payment=F('payment') - 1) # 事物回滚,将全表payment字段自减1的操作撤回 transaction.savepoint_rollback(sid) except Expection as e: transaction.savepoint_rollback(sid) return render(request, 'index.html', local()) # 使用with模块实现 with transaction.atmonic(): pass
六、发送邮件
# 邮件配置信息 EMAIL_USE_SSL = True # Django与邮件服务器的连接方式是否设置ssl模式 # 邮件服务器,如果是163,就改成smtp.163.com EMAIL_HOST = 'smtp.qq.com' # 设置服务器类型,qq邮箱分为SMTP和POP3服务器 # 邮件服务器端口 EMAIL_PORT = 465 # 若使用SMTP服务器,则端口应为465或587 # 发送邮件的账号 EMAIL_HOST_USER = '4512125@qq.com' # 账号必须开启POP3/SMTP服务 # SMTP服务密码 EMAIL_HOST_PASSWORD = 'SFSDDSFSVGSF' # 授权码 # 设置默认发送邮件的账号 DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
实践出真知~