ORM介绍:object relational mapping 对象关系映射


    1> 把面向对象中的类和数据库表一一对应,通过操作类和对象,对数据表实现数据操作,不需要写sql,由orm框架生成。

    2> Django实现了ORM的一个框架,在项目与数据库之间起桥梁作用。

    3> django数据库开发步骤如下:

        a 在models.py定义模型类

        b 生成迁移文件: python manage.py makemigrations  -> 在migrations文件夹生成0001_intial.py

        c 执行迁移生成数据库(默认会用sqite3数据库,生成数据库名为:db.sqlite3)

在数据库中生成对应的数据 test01_department 等

        d 通过模型类和对象,对数据进行增删改查


模型类设计:

    1> 在应用models.py 中编写模型类,必须继承于models.Model类

    2> 在模型类中,定义属性,生成对应的数据库表字段

       属性名 = models.字段类型(字段选项)

    3> 字段类型(初步了解,models包下的类):只要修改了类型,就需要重新迁移


  • AutoField: 自动增长,通常不需要指定,django自动创建名为id的自动增长属性
  • CharField: 字符串,必须指定的参数: max_length 最大字符个数
  • TextFiled: 大文本字段,一般超过4000个字符
  • IntegerField: 整形
  • BooleanField: 布尔,支持Null,True
  • NullBooleanField: 支持Null,True,False
  • DateFiled: [auto_now=False, auto_now_add=False]
  • auto_now 表示自动设置该字段为最后一次修改的时间,默认为False
  • auto_now_add 表示自动设置该字段为创建时的时间,默认为False
  • 两者互斥,不能同时使用
  • DateTimeField: 日期时间
  • DecimalFiled(max_digits=None, decimal_places=None): 
  • 十进制浮点数,适合用于保存金额,精度较高
  • 必须指定参数,max_digits总位数,decimal_places小数位数
  • FloatField: 浮点数,有误差 
  • FileField: 上传文件字段
  • ImageField: 继承与FileFiled,对上传的内容进行校验,确保是有效地图片
  • ForeignKey: 外键,建立一对多关系


    4> 字段选项:通过选项实现对字段的约束


选项

默认值

描述

是否要重新迁移修改表结构

null

False

如果为True,数据库中字段允许为空


unique

False

True表示这个字段在表中必须有唯一值


db_column

属性名称

字段名,如果未指定,则使用属性的名称


primary_key

False

若为True,则该字段会成为模型的主键字段,一般作为AutoField的选项使用


default

-

默认值


blank

False

True,html页面后台填写表单验证时字段允许为空


editable

True

如果设为False, 这个字段将不会出现在管理后台


choices

-

True,html页面表单验证时字段允许为空


    choices-下拉列表:

choices_sex = (
            (0, '男'),
            (1, '女'),
        )
sex = models.IntegerField(default=0, choices=choices_sex)

    5> 元类class Meta的使用:

class Meta:
            # 修改表名(需要迁移)
            db_table = 'department'

            # 修改后台的显示的表名
            verbose_name = '部门'
            # 去除复数形式
            verbose_name_plural = verbose_name

修改和添加类:

from test01.models import *
 
    from datetime import date
 
    d = Department()
 
    d.name = ‘人事部’
 
    d.create_date = date(2019, 1, 1)
 
    d.save()



d.id = None  # 修改id创建新的数据
 
    d.save()
 
    
 
    d.id = 2 
 
    d.delete()  # 删除id=2



模型管理器:

    1> 在django创建对象时,都会默认创建一个object属性,是一个manage类,有以下几种方法:




objects管理器中的方法

返回类型

作用

模型类.objects.get()

模型对象

返回一个对象,且只能有一个


如果查到多条数据,则报:MultipleObjectsReturned 


如果查询不到数据,则报:DoesNotExist

模型类.objects.all()

QuerySet

返回所有的对象

模型类.objects.filter()

QuerySet

返回满足条件的对象

模型类.objects.exclude()

QuerySet

返回不满条件的对象

模型类.objects.order_by()

QuerySet

对查询结果集进行排序

模型类.objects.aggregate()

字典,例如:


{‘salary__avg’: 9500.0}

进行聚合操作


Sum, Count, Max, Min, Avg

模型类.objects.count()

数字

返回查询集中对象的数目




get(), all() 和 employee_set.all()方法:


d = Department.objects.get(id=1)
 
    print(d.name)
 
    ----------------------------------------------------------------------
 
    >>> from test01.models import *
 
    >>> d = Department.objects.all()
 
    >>> d
 
    [<Department: 人事部>, <Department: 人事部>]
 
    >>> e = Employee()
 
    >>> e.name = '张三'
 
    >>> e.age = 20
 
    >>> e.sex = 0
 
    >>> e.salary = 100000
 
    >>> e.comment = '无'
 
    >>> e.department = Department.objects.get(id=1)  # 设置外键
 
    >>> e.save()
 
    >>> e.id = None
 
    >>> e.name = '李四'
 
    >>> e.save()
 
    >>> d = Department.objects.get(id=1) # 重复设置外键
 
    >>> d.employee_set.all()  # employee_set 为django一对多的时候自动生成的属性
 
    [<Employee: Employee object>, <Employee: Employee object>]
 
    ----------------------------------------------------------------------
 
    # 根据员工查部门   
 
    >>> e = Employee.objects.get(id=1)
 
    >>> e.department
 
    <Department: 人事部>
 
增删改: 
    Employee.objects.filter(id=1).delete()
 
    Employee.objects.filter(id=1).update(name=‘行政部')
 
条件查询: 
    1> 判等:exact
 
        # 例:查询id为1的员工
 
        select * from test01_employee where id = 1;
 
        Employee.objects.filter(id__exact=1)
 
        Employee.objects.filter(id=1)
 

 
    2> 模糊查询:contains,endswith/startswith
 
        # 查询包含马的员工
 
        select * from test01_employee where name = “%马%";
 
        Employee.objects.filter(name__contains=‘马’)
 

 
    3> 空查询:isnull
 
        # 查询comment 不为空
 
        select * from test01_employee where comment is not null;
 
        mployee.objects.filter(comment__isnull=False)
 

 
    4> 范围查询:in
 
        # 查询id为1,3,5
 
        select * from test01_employee where id in (1, 3, 5);
 
        Employee.objects.filter(id__in=(1, 3, 5))
 

 
    5> 比较查询:gte(>=), lte(<=), gt(>), lt(<) 
 
        # 查询年龄大于等于30
 
        mployee.objects.filter(age__gte=30)
 

 
 year、month、day、week_day、hour、minute、second
 
        # 查询入职年份为2015
 
        select * from test01_employee where year(hire_date) = 2015;
 
        Employee.objects.filter(hire_date__year=2015)
 
 
        
 
 
        # 查询入职年份在2015-1-1以后
 
 
        select * from test01_employee where hire_date >= date(2015-1-1);
 
 
        from datetime import date
 

 

 
    7> exclude:
 
        # 查询id 不等于 1
 
        select * from test01_employee where id != 1;
 
        Employee.objects.exclude(id=1)
 
关联查询: 
    1> 通过对象:
 
        a. 一对多 departement.employee_set.all()
 
        b. 多对一 employee.department
 

 
    2> 通过模型管理器:
 
        # 查询部门信息,要求部门中员工名字包含马
 
        select * from test01.department as d inner join test01.employee as e 
 
        on d.id = e.department_id where e.name like ‘%马%’;
 

 
        Department.objects.filter(employee__name__contains='马’)
 
        >>> <QuerySet [<Department: 财务部>, <Department: 财务部>]>
 
        
 
        # 查询部门为研发部的所有员工信息
 
        select * from test01.department as d inner join test01.employee as e 
 
        on d.id = e.department_id where d.name = '研发部’
 

 
        Employee.objects.filter(department__name__exact = '研发部’)
 
        >>> <QuerySet [<Employee: 老李>, <Employee: 老王>, <Employee: 王五>]>
 
        
 
F对象:用于比较表中两个字段 
     # 查询age 大于四倍 id
 
from django.db.models import F
 
     Employee.objects.filter(age__gt=F('id') * 4)
 
 
 
 
Q对象:对查询条件进行与或非(&|~)的逻辑操作,多个条件
 

 
    # 查询年龄大于30 且 id 大于3
 
from django.db.models import Q
 
    select * from test01_employee where id > 3 and age > 30;
 
    Employee.objects.filter(id__gt=3, age__gt=30)
 
    Employee.objects.filter(Q(id__gte=3)&Q(age__gte=30))
 
    # 查询id不等于3
 
    Employee.objects.filter(~Q(id=3)) -> 波浪线
 
order_by 方法:排序方法,降序’-属性名’ 
    # 统计id 大于等于3,降序排列
 
    select * from test01_employee where id > 3 order by age desc;  -> [asc升序]
 
    Employee.objects.filter(id__gt=3).order_by('-age')
 
aggregate方法:聚合操作,对多行查询结果的一列进行操作 
    1> 常用聚合类Sum, Count, Max, Min, Avg,返回字典{‘属性名__聚合函数’: 值}
 
    
 
    2> from django.db.models import Count, Avg
 
        
 
       # 查询总人数
 
       select count(*) from test01_employee;
 
       Employee.objects.aggregate(Count('id’))
 
       >>> {'id__count': 10}
 

 
       # 查询工资平均数
 
       select avg(salary) from test01_employee;
 
       Employee.objects.aggregate(Avg('salary’))
 
       >>> {'salary__avg': 9600.0}
 
count()方法:统计总数,返回一个数值 
       # 查询id大于等于3的人数
 
       select count(*) from test01_employee where id >= 3;    
 
       Employee.objects.filter(id__gte=3).count()
 
 
QuerySet 查询集:
 
    1> 为一个数列,下标不能够为负,可以进行切片操作,datas[0:1:-1]
 

 
    2> 拥有get(),同objects管理器相同。
 

 
    3> 拥有exists(),判断数列中是否有数据
 

 
    4> 惰性查询:创建QuerySet的时候不会马上查询数据库,当访问数据的时候才会发起查询操作。
 
 
 
 

 
                datas = Department.objects.all()  # 不会查询
 
    
 
    5> 缓存:当首次查询时,会缓存,再次查询时会使用之前查询的数据, 但是使用索引或者切片操作,就不会缓存
 

 
       datas = Department.objects.all()
 
       # 首次遍历,缓存数据
 
       [deps.name for deps in datas]
 
       # 不会查询数据库
 
       [deps.name for deps in datas]
 
    
 
       datas = Department.objects.all()
 
       # 会查询数据库
 
       datas[0]
 
       # 会查询数据库
 
       datas[0]
 

 
 

 
自关联:查询父级和子级目录
 
    class Area(models.Model):
 
        title = models.CharField(max_length=20)
 
        parent = models.ForeignKey(‘self’, on_delete=models.CASCADE, null=True, blank=True)
 

 
        def __str__(self):
 
            return self.title
 

 
        +------+-----------------------------------------------+-----------+
        | id   | title                                         | parent_id |
        +------+-----------------------------------------------+-----------+
        |    1 | 中国                                          |      NULL |
        |    2 | 北京市                                        |         1 |
        |    3 | 天津市                                        |         1 | 
        +------+-----------------------------------------------+-----------+
 

 
    from app01.models import *
 
    a = Area.objects.get(id=232)
 

 
    # 获得父级
 
    a.parent.title >>> ‘广东省’
 
    
 
    # 获得子级
 
    a.area_set.all()  >>>   ….