乐趣区

关于python3.x:django-orm使用

ORM(Object Relational Mapping)

orm 应用步骤

  1. 在我的项目应用的数据库管理系统中建设数据库。
DATABASES = {
  'default': {'ENGINE': 'django.db.backends.mysql', 
              # 数据库引擎,指明数据库类型
              'HOST': '127.0.0.1',
              # 数据库装置在本机
              'PORT': '3306',
              # 端口号
              'NAME': 'test_orm',
              # 数据库名称
              'USER': 'root',
              # 数据库用户名
              'PASSWORD': 'root',
              # 数据库明码
             }
}
  1. 在我的项目的配置文件 settings.py 中设置数据库的连贯字符。
INSTALLED_APPS = ['利用名称']
  1. 在应用程序的 models.py 文件中编写继承于 models.Model 的数据模型。
  2. 运行 python manage.py makemigrationspython manage.py migrate 两个命令生成数据库表。
  3. 应用 Django ORM 操作数据库表。
# 在 project 文件夹下的_init_中须要应用 pymysql 替换 mysql
import pymysql

pymysql.install_as_MySQLdb()

罕用 orm 字段类型

  • Char Field:字符类型,必须提供 max_length 参数,max_length 示意字符长度。

verbose_name 在 Django Admin 治理后盾是字段的显示名称,可了解为字段别名,verbose_name 在 SQL 层面没有具体的体现,也就是说加不加 verbose_name 对数据库中的字段没影响。

name=models.CharField(max_length=32,verbose_name='姓名')
  • Email Field:邮箱类型,实际上是字符类型,只是提供了邮箱格局测验。
email=models.EmailField(verbose_name='邮箱')
  • Text Field:文本类型,存储大段文本字符串。字符串如果超过 254 个字符倡议应用 Text Field。
descript=models.TextField(verbose_name="简介")
  • Integer Field:整数类型。
int= models.IntegerField()
  • Date Field:日期字段。
date=models.DateField(auto_now=True, auto_now_add=False)

auto_now 参数主动保留以后工夫,个别用来示意最初批改工夫。在第一次创立记录的时候,Django 将 auto_now_add 字段值主动设置为以后工夫,用来示意记录对象的创立工夫

  • Time Field:工夫字段。
time= models.TimeField(auto_now=False, auto_now_add=False)
  • Date Time Field:日期工夫字段,合并了日期字段与工夫字段。
datetime=models.DateTimeField(auto_now=False, auto_now_add=False)
  • File Field:实际上是字符串类型,用来把上传的文件的门路保留在数据库中。文件上传到指定目录,主要参数 upload_to 指明上传文件的保留门路,这个门路与 Django 配置文件的 MEDIA_ROOT 变量值无关。
filetest =models.FielField (upload_to = 'test/')
  • Image Field:实际上是字符串类型,用来把上传的图片的门路保留在数据库中。图片文件上传到指定目录,主要参数 upload_to 指明上传图片文件的保留门路,与 File Field 中 upload_to 雷同。
picture = models.Image Field(upload_to = 'pic/')

常用字段属性

  1. db_index:db_index=True 示意设置此字段为数据库表的索引。
title = models.CharField(max_length=32, db_index=True)
  1. unique:unique=True 示意该字段在数据库表中不能有反复值。
  2. default:设置字段默认值,如 default=’good’。
  3. auto_now_add:Datetime Field、Date Field、Time Field 这 3 种字段的独用属性,auto_now_add=True 示意把新建该记录的工夫保留为该字段的值。
  4. auto_now:Datetime Field、Date Field、Time Field 这 3 种字段的独用属性,auto_now= True 示意每次批改记录时,把以后工夫存储到该字段。

基本操作 CRUD

形式一

new_emp=models.employee.objects.create(name="tom",email="tom@163.com",dep_id=66)

形式二:应用 save 办法

new_emp= models.employee (name="tom",email="tom@163.com",dep_id=66)
new_emp.save()

删除记录,用 filter()过滤出符合条件的记录后调用 delete()删除。

models.employee.objects.filter(name= "张三").delete()
# 将指定条件的记录更新,并更新指定字段的值
models.employee.objects.filter(name='tom').update(email="tom2@163.com")
# 批改单条数据
# 取出单条信息
obj = models.employee.objects.get(id=66)
# 批改
obj.email = "tom2@sina.com"
# 保留批改
obj.save()
# 获取全副
Emp_list= models.employee.objects.all()
# 获取单条数据,数据不存在则报错
Emp=models.employee.objects.get(id=123)
# 获取指定条件的记录集
Emp_group=models. employee.objects.filter(name= "张三")

Django ORM 数据操作罕用函数

Django 的 Query Set 对象集实质上是对应于数据库表的记录汇合,QuerySet 有一个个性就是“惰性”,即返回值为 Query Set 的函数不会立刻去数据库操作数据。当咱们用到 Query Set 的值时,它才会去数据库中获取数据,如遍历 QuerySet、打印 Query Set、判断 Query Set 是否有值时,它才会到数据库表中获取数据。

  • all()函数,返回符合条件的全副记录。
objects = models.employee.objects.all()
  • filter()函数,返回指定条件的记录。filter 前面的括号内为过滤条件,相似于 SQL 中语句 where 前面的条件语句。
objects = models.employee.objects.filter(name='tom')

filter 前面的括号内寄存的是过滤条件,针对数据表的字段过滤个别用“字段名 + 双下划线 + 条件名词”,括号内的过滤条件能够有多个,这些条件之间是“与”关系也就是 and 关系,条件名词在 Django ORM 中次要包含 contains、icontains、in、gt、lt、range、startswith、endswith、istartswith、iendswith 等,局部用法如下。

# 获取 name 字段蕴含“Tom”的记录
models.employee.objects.filter(name__contains="Tom")
# 获取 name 字段蕴含“tom”的记录,icontains 疏忽大小写
models.employee.objects.filter(name__icontains="tom")
# 获取 employee 数据表中 id 等于 10、20、66 的数据
models.employee.objects.filter(id__in=[10, 20, 66])
# 获取 employee 数据表中 id 不等于 10、20、66 的记录,因为后面用的是 exclude
models.employee.objects.exclude(id__in=[10, 20, 66])。# 获取 employee 数据表中 id 大于 1 且 小于 10 的记录,两个过滤条件的关系等价于 SQL 的 and
models.employee.objects.filter(id__gt=1, id__lt=10)
# 获取 employee 数据表中 id 在范畴 1~66 内的记录,等价于 SQL 的 id bettwen 1and 66
models.employee.objects.filter(id__range=[1, 66])
# 获取 employee 数据表中 birthday 字段中月份为 9 月的记录,birthday 为日期格局
models.employee.objects.filter(birthday__month=9)
  • exclude()函数,返回不合乎括号内条件的记录,与 filter()函数具备相同的意义。
objects = models.employee.objects.exclude(name='tom')
  • order_by()函数,依照 order_by 前面括号中的字段排序。
objects = models.employee.objects.exclude(name='tom').order_by('name','id')

字段名中加“-”,示意按该字段倒序排列。如下代码示意,按 name 字段倒序排列列表。

objects = models.employee.objects.order_by('-name')
  • distinct()函数,去掉记录汇合中齐全一样的记录(重复记录),而后返回这个记录集。
objects = models.employee.objects.filter (name='tom').distinct()
返回 QuerySet

以下 3 个函数返回其余数据类型,能够了解为非凡的 Query Set 类型。

  • values()函数,返回一个字典类型序列。
objects = models.employee.objects.values('id','name','email')
print(objects)

输入如下

<Query Set[{'id': 1, 'name': '刘大华', 'email': 'ldh@163.com'}, {'id': 2, 'name': '古连田', 'email': 'glt@123.com'}, {'id': 4, 'name': '张三', 'email': 'zs@sina.com'}]>
  • values_list()函数,返回一个元组类型序列。
objects = models.employee.objects.values_list('id','name','email')
print(objects)

输入如下

<Query Set[(1, '刘大华', 'ldh@163.com'), (2, '古连田', 'glt@123.com'), (4, '张三','zs@sina.com')]>
  • get()、first()、last()返回单个对象,能够了解为返回数据表中的一条记录。
# 返回 id 为 1 的记录,括号内是过滤条件
object1 = models.employee.objects.get(id=1)
# 返回数据集的第一条记录
object2 = models.employee.objects.first()
# 返回数据集的最初一条记录
object3 = models.employee.objects.last()
# 返回数据集的个数
object4= models.employee.objects.count()

跨表操作

Django 中的数据模型关联关系次要是由外键、多对多键、一对一键造成的关联关系,Django 数据模型的实例对象中保留着关联关系相干的信息,这样在跨表操作过程中,咱们能够依据一个表的记录的信息查问另一个表中相关联的记录,充分利用关系型数据库的特点。

Foreign Key 字段

在数据模型中个别把 Foreign Key 字段设置在“一对多”中“多”的一方,Foreign Key 能够和其余表做关联关系,也能够和本身做关联关系。

  • Foreign Key 字段个别在 models.py 文件的数据模型类中定义,其模式如下。
# 员工的部门,外键,造成一对多的关系
dep=models.ForeignKey(to="department",to_field="id",related_name="dep_related",on_delete=models.CASCADE)
  • Foreign Key 字段次要有 4 个属性,如下。

    • to 用来设置要关联的表,形如 to=”tname”,其中 tname 就是要关联的数据模型。
    • to_field 用来设置要关联的字段,形如 to_field=”id”,Django 默认应用被关联对象的主键,个别不必设置。
    • related_name 是在反向操作时应用的名字,用于代替原反向查问时的“表名_set”,形如 related_name=”dep_related”,如果这样定义,dep_obj.employee_set.all()就要被 dep_obj.dep_related.all()代替。

      • 如果应用了 related_name,在反向操作中就不能用“表名_set”。
    • 属性 on_delete=models.CASCADE 用来删除关联数据,与之关联的数据也要删除。这是该属性的惯例设置,另外还可将其设置成 models.DO_NOTHING、models.PROTECT、models.SET_NULL、models.SET_DEFAULT,这些设置不罕用
外键跨表关联操作

正向:单 -> 多

反向:多 -> 单

首先介绍一下数据操作的惯例说法,正向操作 是指由存在外键的表通过外键查找关联的数据库表,反向操作指的是由关联表查找存在外键的数据库表。

以后面定义的 employee 数据表与 department 数据表为例,正向操作是通过 employee 的一条记录的外键查找与之关联的 department 的记录,代码如下。

emp=employee.objects.get(id=2)
dep=emp.dep.dep_name

用 emp.dep.dep_name 获得员工所在部门的名称,其中 emp 是保留 employee 的一条记录对象的变量,dep 为外键名字。

反向操作 是通过 department 的一条记录查找 employee 中关联的记录,用“表名_set”,其中表名用的是含有外键字段的表的名称,代码如下。

dep_obj=department.objects.get(id=8)
emp_list=dep_obj.employee_set.all()

通过 dep_obj.employee_set.all()获得一个部门的所有员工名,dep_obj 是存储 department 的一条记录对象的变量,“employee_set”就是“表名_set”的模式。

外键跨表操作的样例
  • 创立 url 与视图关联
path('test_foreign/',test_foreign)
  • 在 /test_orm/employee/views.py 中编写 test_foreign 代码。
def test_foreign(request):
  # 取出 employee 的一条记录
  emp=employee.objects.get(id=16)
  # 正向操作,通过外键值 dep 关联到 department 数据表的一条记录,而后获得该记录的 dep_name 字段
  dep_name=emp.dep.dep_name
  dep_obj=department.objects.get(id=6)
  # 反向操作,通过 employee_set 关联到 employee 数据表,而后用 all()函数获得其全副记录
  emp_list=dep_obj.employee_set.all()
  for item in emp_list:
    print(item)
外键跨表查问字段

查问字段的值也分正向操作与反向操作两种模式。

  • 正向操作查问字段值,获得字段值的模式为“外键 + 双下划线 + 关联表的字段名”,如下所示。
emp=models.employee.objects.values_list('name',"dep__dep_name","dep__dep_script")
print(emp)
emp2=models.employee.objects.values('name',"dep__dep_name","dep__dep_script")
print(emp2)

values_list()和 values()函数传入的参数:name 取的是 employee 数据表中的字段;dep__dep_name 是“外键 + 双下划线 + 关联表的字段名”的模式,它通过 employee 外键 dep 关联到 department 数据表,而后获取 dep_name 的值;dep__dep_script 也通过外键获得关联表的 dep_script 字段的值。

  • 反向操作查问字段值,获得字段值的模式为“表名 + 双下划线 + 字段名”,表名是有外键字段的表的名称,如下所示。
dep_emp=models.department.objects.values_list("employee__name")
print(dep_emp)

如果在外键字段定义了 related_name 属性,就必须用 related_name 指定的名字取字段,模式如“related_name 值 + 双下划线 + 字段名”

举例:

employee/module.py

dep=models.Foreign Key(to="department",to_field="id",related_name='dep_related',on_delete=models.CASCADE)

depmartment/views

dep_emp=models.department.objects.values_list("dep_related__name","dep_related__email")
与多对多键无关的跨表操作
  • Many To Many Field 字段

Many To Many Field 字段个别在 models.py 文件的数据模型类中定义,其模式如下。

# 员工退出的个人,多对多关系,即一个员工能够退出多个个人,一个个人能够有多个员工
group=models.ManyToManyField(to="group",related_name="group_related")

Many To Many Field 字段次要有 to 和 related_name 两个属性,这两个属性与 Foreign Key 字段的同名属性意义雷同

  • 多对多键跨表关联操作

    这里也波及正向操作与反向操作,正向操作指的是从有多对多键的表 (employee) 查找关联表(group),反向操作指的是从关联表查找有多对多键的表。跨表操作次要用函数进行。

    • create()函数,创立一个新的记录并保留在数据库表中,最初将它增加到关联对象集(记录集)之中
    # 正向操作
    models.employee.objects.first().group.create(group_name='搏击',group_script='搏击也是健身我的项目')
    # 反向操作
    models.group.objects.first().employee_set.create(name='tom',email='wy@163.com',dep_id='11')
    # 反向操作
    models.group.objects.get(id=4).employee_set.create(name='john',email='lm2@163.com',dep_id='11')
  • add()函数取出数据库表中的记录,而后将其增加到关联数据表的记录集。

    第一行代码先把 group 的记录取出来放到变量 group_list 中,第二行代码把取出的记录通过 group.add(group_list)关联到 models.employee.objects.first()取出的记录上,留神变量前要加“”号。同理能够通过 id 值进行关联,以下代码是把 group 中 id 值为 1、2、6 的记录关联到 employee 表的第一条记录上,留神列表变量前要加“*”号。

# 取出一条关联表的信息
group_list=models.group.objects.filter(id=6)
# 塞进多对多表
models.employee.objects.first().group.add(*group_list)
  • set()函数,更改数据库表中记录的关联记录,不论该记录以前关联任何记录,用新的关联替换

    上面代码用 group 数据表中 id 值为 4、5、6 的记录关联 employee 数据表中 id 值为 11 的记录,留神列表变量前不加“*”号。

models.employee.objects.get(id=11).group.set([4,5,6])
  • remove()函数,从记录对象中删除一条关联记录,参数为关联数据库表的 id。

    上面代码是从 employee 数据表中取出第一条记录,而后删除这条记录关联的 group 数据表中 id 值为 4 的记录。

obj_list = models.employee.objects.all().first()
obj_list.group.remove(4)
  • clear()函数,从记录对象中删去所有关联记录。
models.employee.objects.last().group.clear()
多对多关联跨表查问字段值

多对多关联跨表查问字段值也分正向操作与反向操作两种模式

  1. 正向操作查问字段值,获得字段值的模式为“多对多键 + 双下划线 + 关联表的字段名”

id 和 name 为 employee 数据表中字段,group__group_name 能够取 group 数据表中的 group_name 字段的值,返回值 emp_m2m 是元组格局

emp_m2m=models.employee.objects.values_list("id","name","group__group_name")
print(emp_m2m)

# 返回
<Query Set[(1, '李立', '登山团队'), (1, '李立', '游泳队'), (1, '李立', '自行车队'), (2, 'sales', '登山团队'), (2, 'sales', '游泳队'), (2, 'sales', '自行车队'), (3, '张坏蛋', '游泳队'), (3, '张坏蛋', '自行车队'), (10, '刘七云', '登山团队'), (10, '刘七云', '游泳队'), (10, '刘七云','自行车队'), (13, '张三', '登山团队'), (13, '张三', '游泳队'), (13, '张三', '自行车队'),(13, '张三', '跑酷'), (14, 'tom', '登山团队'), (14, 'tom', '游泳队')]>
  1. 反向操作查问字段值,获得字段值的模式为“表名 + 双下划线 + 字段名”,表名用的是存在多对多键字段的表的名称
emp_m2m=models.group.objects.values("group_name","employee__name","employee__email")
# 返回的一个字典列表
print(emp_m2m)

# 返回
<Query Set[{'group_name': '游泳队', 'employee__name': '李立', 'employee__email':'ll@163.com'}, {'group_name': '游泳队', 'employee__name': 'sales','employee__email':'sales@163.com'},…

提醒:如果在多对多键字段中定义了 related_name 属性,就必须用 related_name 指定的值取字段,模式如“related_name 值 + 双下划线 + 字段名”。

与一对一键无关的跨表操作

  1. One To One Field 字段

一对一的关联关系把原本能够存储在一个表的字段拆开别离搁置在两个表中,将查问次数多的字段放在一个表中,将查问次数较少的字段放在另一个表中,而后为两个表建设一对一的关联关系。

module.py

class employeeinfo(models.Model):
  phone = models.CharField(max_length=11)
  address = models.Char Field(max_length=50)
  
class employee(models.Model):
  # 一对一字段
 info=models.OneToOneField(to='employeeinfo',related_name="info_related",on_delete=models.CASCADE)
  1. 一对一键跨表关联操作

一对一键跨表关联操作也波及正向操作与反向操作,正向操作从有一对一键的表查找关联表,反向操作从关联表查找有一对一键的表。

正向操作和反向操作代码如下,其模式与外键根本一样,只是反向操作不必“表名_set”而用间接关联表名,形如“表名”。

提醒:如果应用了 related_name,在反向操作中就不能用“表名”

# 正向操作
emp=models.employee.objects.get(id=1)
dep=emp.info.phone
emp_info = models.employeeinfo.objects.get(id=2)
# 反向操作,因为定义了 related_name="info_related",所以用 info_related
emp_name = emp_info.info_related.name
# 反向操作第二种办法
# 如果在 models.py 的 employee 类中的 info 字段未定义 related_name="info_related",能够用以下形式
# 一对一反向操作不必 employee_set,间接用 emp
emp_info = models.employeeinfo.objects.get(id=2)
emp_name = emp_info.employee.name
  1. 一对一关联跨表查问字段值

一对一关联跨表查问字段值有正向操作与反向操作两种模式,列举代码如下,与外键关联模式雷同。

# 正向操作查问字段值
emp_one=models.employee.objects.values("id","name","info__phone","info__address")
# 反向操作查问字段值。emp_one2=models.employeeinfo.objects.values("phone","address","employee__name","employee__email")

Django 聚合与分组查问

在 Django ORM 中,但凡可能查询数据库表记录的语句都能够称为查问语句,如 models.employeeinfo. objects.get(id=2)、models.employee.objects.filter(name=’tom’)等可能返回数据库表记录集的语句都是 Django ORM 查问语句。

Django ORM 查问语句反对链式操作,在查问语句的前面加上“.aggregate()”就是利用聚合查问,在查问语句的前面加上“.annotate()”就是利用分组查问

聚合查问

聚合查问次要对“.aggregate()”后面的查问语句获得的数据库表记录进行聚合计算。聚合计算次要有求共计值、求平均值、求最大值、求记录数等,因而 aggregate()的参数次要是聚合函数 Avg()、Sum()、Max()、Min()、Count()等

  • Sum

id__lt将筛选出 id 小于 5 的数据,Sum 将他们加起来

# 假如在 employee 数据库表中有一个 salary 字段

# module.py
class employee(models.Model):
  …
  salary=models.DecimalField(max_digits=8,decimal_places=2)


# view.py
def aggreagate(request):
  salarySum = employee.object.filter(id__lt=5).aggregate(Sum('salary'))

聚合查问返回一个蕴含一些键值对的字典,返回值模式如下,这里能够看到返回值键名为“字段名 + 双下划线 + 聚合函数”

{'salary__sum': Decimal('89787.76')}

指定返回名称

salarySum = employee.object.filter(id__lt=5).aggregate(salary__sum = Sum('salary'))

  • 增加多个聚合查问
from django.db.models import Sum,Avg,Max,Min,Count

salary_data =     models.employee.objects.filter(id__lt=18).aggregate(count=Count("id"),salary_hj=Sum("salary"),salary_pj=Avg("salary"),salary_zd=Max("salary"),alary_zx=Min("salary"))

print(salary_data)
# 返回
{'count': 6, 'salary_hj': Decimal('89787.76'), 'salary_pj': 14964.626667,'salary_zd': Decimal('56666.88'), 'alary_zx': Decimal('888.00')}

分组查问

分组查问对“.annotate()”后面的查问语句返回的数据库表记录进行分组聚合计算,依据后面的查问语句是否含有 values()函数进行分组聚合计算

  1. 查问语句不含 values() 函数
# views.py
def get_salary_count(request):
  # models.employee.objects 失去 employee 中所有的记录(员工记录),有 n 个员工,就分 n 个组,每一组再由 annotate()中的聚合函数进行分组统计
  # 返回 employee 数据表中全副记录,并且为每一条记录加一个新字段 groupnum
    empList = employee.objects.annotate(groupnum=Count('group'))
    
    for item in empList:
        print(item.name, ': 加入', item.groupnum, '个个人')
    return HttpResponse('success')
  • 统计每一个部门薪水最高值
# views.py
def dep_list_max:

# Max("employee__salary")中的 employee__salary 通过双下划线获得关联表的字段值。dep_list=models.department.objects.annotate(maxsalary=Max("employee__salary")    
for dep in dep_list:                                            print(dep.dep_name,dep.maxsalary)
  1. 查问语句蕴含 values() 函数
# 上面代码中“values('dep')”起的作用就是以 dep 值分组字段,相当于 SQL 语句中的 group by dep。代码实现的性能就是计算每个部门员工的平均工资
dep_salary=models.employee.objects.values('dep').annotate(avg=Avg("salary")).values('dep__dep_name',"avg")

# 返回
<Query Set[{'dep__dep_name': '审计部', 'avg': 56666.88}, {'dep__dep_name': '经营部','avg': 12833.0}, {'dep__dep_name': '财务部', 'avg': 1000.0}, {'dep__dep_name':'资产管理中心', 'avg': 3227.44}]>

Djangoz 中的 F 函数和 Q 函数

F 函数 => Find

要实现字段值与字段值的比拟或运算操作等就要用到 F 函数,在 F 函数中传入字段名就能获得字段的值。这个函数较易了解,这里只简略介绍。

以下代码实现 id 值小于 30 的员工的薪水减少 600 的性能。

from django.db.models import 

Fmodels.employee.objects.filter(id__lt=30).update(salary=F("salary")+600)

Q 函数 => Query

在 Django ORM 查问语句中,filter()等函数中传入的条件参数是“与”关系,它相当于 SQL 语句的“AND”。通过把条件参数传入 Q 函数,再把各个 Q 函数与“&”“|”“~”操作符进行组合生成简单的查问条件。其中,“&”示意与(AND)关系,“|”示意或(OR)关系,“~”示意反(NOT)关系

  • 在 employee 数据表中查问 id 值小于 30 或者 salary 值小于 1000 的记录。
from django.db.models import 

Qobj=models.employee.objects.filter(Q(id__lt=30)|Q(salary__lt=1000))
  • 查问 employee 数据表中 salary 值大于 1000 并且 name 字段值结尾不是“李”的记录。
from django.db.models import 
Qobj=models.employee.objects.filter(Q(salary__gt=1000)&~Q(name__startswith='李'))饭店啦
退出移动版