Django Web应用开发实战第七章

一、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
实践出真知~
原文地址:https://www.cnblogs.com/NolaLi/p/14392173.html