(二) Django模型models

2018-03-20  本文已影响41人  fanhang64

模型models

一. 配置数据库

(1) 修改工程目录下的__init__.py, 添加

import pymysql
pymysql.install_as_MySQLdb()

(2) 修改settings.py文件, 修改为

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day36',  # 数据库名
        'USER': 'fanzone',
        'PASSWORD': '123',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

二. 开发流程

1. 配置数据库
2. 创建app
3. 创建模型类
4. 生成迁移文件
5. 创建表结构
6. 对model的增删改查
7. 找到views.py文件写入控制器(视图函数)
8. 配置路由 urls.py在工程目录下
9. 创建模板文件夹
10. 在settings.py配置模板路径
11. 在控制器里使用render()方法 访问模板

三. ORM 对象关系映射

概述: 对象-映射

任务:

  1. 根据对象的类型生成表结构
  2. 将对象列表的操作, 转换为SQL语句
  3. 将SQL语句查询到的结果转换为对象和列表

四. 定义模型

(1) 模型-属性-表-字段之间的关系

一个模型类对应数据库中的一个表, 在模型类中定义的属性对应表中的字段名称

(2) 定义字段属性

(3) 创建模型类

在models.py文件中创建类

(4) 元选项

在模型类中定义一个Meta类, 用于设置元信息

db_table: 自定义设置表名 推荐使用小写字母, 数据表名, 默认为 app名称_类名小写

ordering: 查询数据时, 按照某个字段升序或降序查询, 默认升序

实例:

# 学生表
class Students(models.Model):
     pass
    class Meta:
        db_table = 'student'  # 设置当前表名
        # ordering = ['pk']  # 按照主键升序查询
        ordering = ['-pk']   # 按照主键降序查询,前面带有可选的“-”前缀表示倒序

五. 模型成员

类属性

1. objects 管理器

objects是Manager类型的一个对象, 作用是与数据库进行交互

当定义模型类的时候, 若没有指定管理器 django会为你默认创建一个名为objects的管理器

2. 自定义管理器的名称

# 学生表
class Students(models.Model):
    stuObj = models.Manager()  # 自定义管理器名称,若指定,则objects不会创建

同时把视图中的代码改为

def stuShow(request):
    myDict = {}
    # myDict['stu'] = Students.objects.all()
    myDict['stu'] = Students.stuObj.all()  # 新修改的stuObj

3. 自定义管理器Manager类

一个模型可以有多个模型管理类

操作:

重写父类的get_queryset()方法

实例:

class StudentsManager(models.Manager):
    def get_queryset(self):  # 重写父类的方法
      return super(StudentsManager,self).get_queryset().filter(isDelete=True)# 过滤,符合条件的要
      #return super(StudentsManager,self).get_queryset().exclude(isDelete=True) # 符合条件的不要
class Students(models.Model):  # 学生表
    ...
    stuObj2 = StudentsManager()  # 增加了自己过滤的新的manage管理器

六. 创建对象

(1) 目的

向数据库中添加数据, 当创建对象的时候django不会对数据库进行读写的操作, 当调用save()时候才与数据库交互

(2) 实现方法

1. 在模型类中增加一个类方法

__init__()方法已经在基类models.Model中使用, 在自定义模型中无法使用重写. # ?

实例:

# 学生表
class Students(models.Model):
   pass
   # 类方法是可以不通过当前对象实例化去调用的,通过当前的类名.类方法([参数])
   # cls 代表Students类,类方法第一个参数为cls
   @classmethod  # 装饰器声明为类方法
   def addStudents(cls, sname, ssex, sage, scontented, sgrade):
       stu = cls(sname=sname,ssex=ssex,sage=sage,scontented=scontented,sgrade=sgrade)
       return stu

在视图中的操作

def addStudents(request):
   # stu = Students()
   # stu.sname ='李四'
   ..
   # 通过类方法添加
   stu = Students.addStudents('赵六', True, 20, '我是赵六', Grades.objects.get(pk=1))
   stu.save()
   return HttpResponse('添加学生成功')
2. 在自定义管理器中添加一个方法

实例:

class StudentsManager(models.Manager):
    def get_queryset(self):
       pass
    def addStudents(self, sname, ssex, sage, scontented, sgrade):
        # stu = Students()  # ok
        stu = self.model()  # 同上 当模型类名称发生改变 不需要更改当前类名称
        stu.sname = sname
        stu.ssex = ssex
        stu.sage = sage
        stu.scontented = scontented
        stu.sgrade = sgrade
        return stu

在视图中使用

def addStudents(request):
    # 通过自定义管理器的方法添加
    stu = Students.stuObj2.addStudents('赵六11', True, 20, '我是赵六11', Grades.objects.get(pk=1))
    stu.save()
    return HttpResponse('添加学生成功')

七. 模型的查询

概述:

  1. 查询集(queryset)表示从数据库获取对象的集合
  2. 查询集可以有多个过滤器
  3. 过滤器就是一个函数, 基于所给的参数, 去限制查询集
  4. 从SQL角度来说, 查询集合select语句是等价, 过滤器就像where条件

(1) all() 返回查询集中的所有数据/对象

实例:

类名.objects.all()  # 返回所有的数据,列表的形式返回(queryset查询集)
myDict['stu'] = Students.stuObj.all()[0:2]  # 取两条数据 0 1
stu = Students.stuObj.all()[-1]  # error 不支持负索引

通过all()和索引取值做分页例子:

# 学生信息分页
def stuPage(request, nowPage):
    myDict = {}
    myDict['stu'] = Students.stuObj.all()[(int(nowPage)-1)*2:int(nowPage)*2]  # 分页,每页显示2条数据
    # print(type(nowPage))  # str 接收到的nowPage为字符串类型
    return render(request, 'myApp/stuShow.html', myDict)

url配置:

url(r'stuPage/(\d+)/', views.stuPage),  # () 子存储取值传递给nowPage

(2) filter() 返回符号条件的数据

得到的是一个集合的对象, 即queryset

一个条件的情况:

filter(键=值)

Students.objects.filter(sname='张三')  # 返回包含sname为张三的列表

多个条件的情况:

filter(键=值, 键=值, ...) # 多个条件之间是并且的关系

myDict['stu'] = Students.stuObj.filter(sname='张三', ssex=False)  # 返回sname='张三',性别为女的列表

(3) exclude() 过滤掉符合条件的数据

exclude(键=值, 键=值, ...) # 多个条件之间是并且的关系

myDict['stu'] = Students.stuObj.exclude(sname='张三', ssex=False)  # 返回除了sname='张三',性别为女的对象的查找集

(4) order_by('字段名') 排序

升序/降序

格式为:

类名.objects.order_by('字段名')  # 升序
类名.objects.order_by('-字段名')  # 添加- 表示降序
myDict['stu'] = Students.stuObj.filter(ssex=True).order_by('-id') # 查询条件为 性别为True 按照id降序排列

(5) reverse() 对查询查找集进行反转

格式为: order_by().reverse()

实例:

myDict['stu'] = Students.stuObj.all().order_by('-id').reverse()  # ok 为查找集进行反转
myDict['stu'] = Students.stuObj.all().reverse() # 不起作用, 必须要和order_by配合使用

(6) values() 返回查找集, 以列表的形式返回多个字典, 字典的键为字段的名称

实例:

myDict['stu'] = Students.stuObj.values()  # 返回查找集, 返回所有的字段的字典
myDict['stu'] = Students.stuObj.values('sname','ssex') # 返回sname和ssex字段的查找集, 返回多个字典,字典中的字段名为键
myDict['stu'] = Students.stuObj.filter(sname='张三').values('sname','ssex')  # 返回姓名为张三的sname和ssex字段

(7) values_list() 以列表形式 返回包含的多个元组(每个元素是一个元组), 只包含值, 不包含字段

实例:

# 返回查找集,以列表形式 返回包含的多个元组
myDict['stu'] = Students.stuObj.filter(sname='张三').values_list('sname','ssex')  # 返回姓名为张三的sname和ssex字段

八. 返回单个数据

(1) get() 返回一条数据(一个对象)

实例:

stu = Students.stuObj.get()  # error 多条数据
stu = Students.stuObj.get(pk=20) # error 没有找到符号条件
stu = Students.stuObj.get(pk=1)  # ok  Students object 返回对象
# 下面这俩中结果一样
Students.stuObj.filter(sname='李四')[0] <==> Students.stuObj.get(pk=1)  # 为对象

注意:

  1. 如果没有找到符合条件的对象, 会引发模型类的models.DoesNotExist异常错误
  2. 如果查询的数据超过一条, 会引发模型类的models.MultipleObjectsReturned异常

(2) count() 统计查询结果集中的对象的个数

格式:

类名.objects.all().count()  # 统计所有数据的条数

实例:

Students.objects.all().count()  # 统计所有数据的条数
Students.objects.filter(ssex=True).count()  # 统计ssex为男的个数

(3) first()/last() 返回查询结果的第一个/最后一个对象

实例:

Students.objects.filter(ssex=True).first()  # 第一个对象, filter返回列表,返回列表中的第一个对象
stu = Students.stuObj.filter(ssex=True).first().sname  # 张三  返回性别为男的第一个对象的name
Students.objects.filter(ssex=True).last()  # 最后一个对象

(4) exists() 判断queryset是否包含数据 如果包含返回True, 否则为False

实例:

Students.objects.filter(ssex=True).exists()  # True
Students.objects.filter(pk=20).exists()  # False

(5) 字段值的修改

save() : 更适合单条数据的修改

update() : 适用于多条数据

zs = Students.stuObj.get(sname='张三')
zs.sname = '张三三'
zs.save()  # 适用于单条数据的修改
Students.stuObj.get(sname='张三三').update(sname='张三')  # error update为queryset的查询集的方法
Students.stuObj.filter(sname='张三三').update(sname='张三')  # ok
Students.stuObj.all().update(isDelete=False)  # ok
Students.stuObj.all().update(isDelete=False, ssex=False)  # 修改多个字段,

九. QuerySet 字段比较运算符

(1) 完全匹配运算符

  1. __exact:大小写敏感
  2. __iexact:忽略大小写

实例:

Students.stuObj.filter(sname__exact='ab') # 三个结果相同
Students.stuObj.filter(sname='ab')  # 同上
Students.stuObj.filter(sname__iexact='ab')  # 同上

(2) 是否包含

  1. __contains: 大小写敏感
  2. __icontains:忽略大小写

实例:

Students.stuObj.filter(sname__contains='A')  # ok AB
Students.stuObj.filter(sname__icontains='A')  # 忽略大小写 aB AB

(3) 以..开头/以..结尾

  1. __startswith:大小写敏感
  2. __istartswith:忽略大小写
  3. __endswith:大小写敏感
  4. __iendswith:忽略大小写

实例:

myDict['stu'] = Students.stuObj.filter(sname__startswith='A')  # AB 以A开头
myDict['stu'] = Students.stuObj.filter(sname__startswith='a')
myDict['stu'] = Students.stuObj.filter(sname__istartswith='A') # AB ab 忽略大小写
myDict['stu'] = Students.stuObj.filter(sname__endswith='三')  # 以 '三' 结尾

(4) 是否为空

  1. __isnull:判断为空

值为: True和False

实例:

Students.stuObj.filter(sname__isnull = False)  # 查找sname不为空
Students.stuObj.filter(sname__isnull = True)  # 查找snmae为空

(5) 在..范围里

  1. __in:

实例:

Students.stuObj.filter(pk__in = [1,2,3,10])  # id在1,2,3,10中的
Students.stuObj.exclude(pk__in = [1,2,3,10])  # id不在1,2,3,10中的

(6) 在..范围内 相当于between..and

  1. __range

实例:

Students.stuObj.filter(pk__range = [1,3])  # id为 1-3 范围内的,包括3

(7) 比较

  1. __gt:大于
  2. __gte:大于等于
  3. __lt:小于
  4. __lte:小于等于

实例:

myDict['stu'] = Students.stuObj.filter(id__gt=3)  # id大于3的
myDict['stu'] = Students.stuObj.filter(id__gte=3)  # id大于等于3的
myDict['stu'] = Students.stuObj.filter(id__lt=3)  # id小于3的
myDict['stu'] = Students.stuObj.filter(id__lte=3)  # id小于等于3的

(8) 时间

  1. __year
  2. __month
  3. __day
  4. __week
  5. __hour
  6. __minute
  7. __second

实例:

Students.stuobj.filter(lasttime__year=2018)  # 返回符合条件的对象列表, 最后修改时间的年份为2018的

(9) 聚合函数

  1. Avg() # 返回所给字段的平均值, 返回类型: float
  2. Count() # 根据所给的关联字段返回被关联 model 的数量
  3. Max() # 返回所给字段的最大值
  4. Min() # 返回所给字段的最小值
  5. Sum() # 计算所给字段值的总和

导入模块

from django.db.models import Max,Min

配合函数aggregate() 函数去使用

实例:

Students.objects.aggregate(Max('sage')) # 查询年龄最大的值

(10) F对象

概念: 可以使用模型的A属性与B属性比较

导入: from django.db.models import F, Q

实例:

# f对象的控制器
def f(request):
    fg = Grades.objects.filter(ggirlnum__gt=F('gboynum'))  # 返回girl数量大于boy数量的集合
    print(fg[0].gname)
    return HttpResponse(fg)

(11) Q对象

概述: 进行条件的或运算

可以组合使用 &(and), |(or), ~(not)操作符, 当一个操作符是用于两个Q的对象, 它产生一个新的Q对象。

导入: from django.db.models import F, Q

实例:

s = Students.stuObj.filter(id__gt=3)  # id大于3
s = Students.stuObj.filter(Q(id__gt=3)|Q(id__lt=3))  # 查询id大于3或id小于3的queryset,不包含3
# select * from 表名 where id > 3 or id <3;
s = Students.stuObj.filter(Q(sname='张三'), Q(id__gt=3)|Q(id__lt=3))  # 查询id大于3或id小于3的queryset,不包含3   -------------> filter的逗号进行并操作,可用|进行或操作
# select * from 表名 where sname = and (id >3 or id <3)
for i in s:
    print(i.sname)
return HttpResponse('Q对象')

(12) 删除

.delete() # 在数据库中删除数据

实例:

Students.objects.filter(pk_gt=1).delete()  # 把主键大于1的数据在数据库中删除

注意:

id/pk/exact, 三种写法结果一样

Students.objects.filter(id=1)
Students.objects.filter(pk=1)
Students.objects.filter(id_exact=1)
上一篇下一篇

猜你喜欢

热点阅读