django学习笔记(六)-----模型

一、django

对各种数据库提供了很好的支持,django为这些数据库提供了统一的调用API,可以根据不同的业务需求选择不同的数据库

二、配置数据库

(1)修改工程文件(project)下__init__.py文件

import pymysql
pymysql.install_as_MySQLdb()

(2)修改settings.py文件

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':  'sunck',    #你的数据库名称
        'USER': 'root',   #你的数据库用户名
        'PASSWORD': '123456', #你的数据库密码
        'HOST': '', #你的数据库主机,留空默认为localhost
        'PORT': '3306', #你的数据库端口
        'OPTIONS': {
            'init_command': "SET sql_mode='traditional',default_storage_engine=INNODB;"#设置数据库为INNODB,为第三方数据库登录用
            },
    }
}

三、开发流程

(1)配置数据库
(2)定义模型
一个模型类都在数据库中对应一张数据表
(3)生成迁移文件
(4)执行迁移生成数据表
(5)使用模型类进行增删改查

四、ORM

1、概念

对象-关系-映射

2、任务

(1)根据对象的类型生成表结构
(2)将对象、列表的操作转换为sql语句
(3)将sql语句查询到的结果结果转换为对象、列表

3、优点

极大的减轻了开发人员的工作量,不需要面对面对数据库的变更而修改代码

4、图解(如下图)

在这里插入图片描述

五、定义模型

1、模型、属性、表,字段间的关系

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

2、定义属性

(1)概述

1)django根据属性类型确定以下信息

  • 当前选择的数据库支持字段的类型
  • 渲染管理表单时使用的html控件
  • 在管理站点最低限度的验证

2)django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列

3)属性命名限制

  • 遵循标识符规则
  • 由于django的查询方式,不允许使用连续的下划线(两个也不行)

(2)库

1)定义属性时, 需要字段类型, 字段类型被定义在django.db. models.fields目录下,为了方便使用,被导入到django.db.models中
2)使用方式

  • 导入from django.db import models
  • 通过models.Field创建字段类型的对象,赋值给属性

(3)逻辑删除

对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete
属性,类型为BooleanField,默认值为False

字段类型(字段选项)

(4)字段类型

1)models.AutoField()

  • 一个根据实际ID自动增长的IntegerField, 通常不指定
  • 如果不指定,一个主键字段将自动添加到模型中

2)CharField(max_ length=字符长度)
字符串,默认的表单样式是TextInput

3)models.TextField()
大文本字段,一般超过4000字节使用,默认的表单控件是Textarea

4)models.IntegerField()
整数

5)DecimalField(max_digits=None, decimal_places=None)

  • 使用python的DecimalField实例表示的十进制浮点数3.1415926----->DecimalField(8,7)
  • 参考说明
    (1)DecimalField.max_digits位数总数
    (2)DecimalField.decimal_places小数点后的数字位数

6)FloatField
用python的float实例来表示的浮点数

7)BooleanField(default=False默认否)或者(default=True默认是)
true/false字段,此字段的默认表单控制是CheckboxInput

8) NullBooleanField
支持null、true、 false三种值

9)DateField[auto_now=False, auto_now_ add=False ])

  • 使用Python的datetime.date实例表示的日期
  • 参数说明
    (1)DateField.auto_now
    每次保存对象时,自动设置该字段为当前时间,用于
    最后一次修改”
    的时间戳,它总是使用当前日期,默认为false
    (2)DateField.auto_now_add
    当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
  • 说明
    该字段默认对应的表单控件是一个TextInput。在管理员站点添加了一个JavaScript写的日历控件,和一个"Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
  • 注意
    auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果,写一个就行

10)TimeField
使用Python的datetime.time实例表示的时间,参数同DateField

11)DateTimeField
使用Python的datetime .
datetime实例表示的日期和时间,参数同DateField

12)FileField
一个上传文件的字段

13)ImageField
继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image(传的是一个图片)

(5)字段选项

1)概述
通过字段选项,可以实现对字段的约束
在字段对象时通过关键字参数指定

2)null
如果为True, Django 将空值以NULL 存储到数据库中,默认值是False

3)blanke
.如果为True, 则该字段允许为空白,默认值是False

4)注意
null是数据库范畴的概念,blank 是表单验证证范畴的

5)db_ column
字段的名称,如果未指定,则使用属性的名称sage=models.IntegerField(db_column=“age”),数据库中age,这里还是sage

6)db_ index
若值为True, 则在表中会为此字段创建索引

  1. default
    默认值

8)primary_key
若为True,则该字段会成为模型的主键字段

9)unique
若为True,这个字段在表中必须有唯一值

(6)关系

1)分类

  • ForeignKey:一对多,将字段定义在多的端中
  • ManyToManyField; 多对多,将字段定义在两端中
  • OneToOneField: 一对一,将字段定义在任意一端中

2)用一访问多

  • 格式
    对象.模型类小写_ set
  • 示例
    grade . students_ set

3)用一访问一

  • 格式
    对象.模型类小写
  • 示例
    grade.students

4)访问id

  • 格式
    对象.属性_id
  • 示例
    student.sgrade_id

3、创建模型类

想要更改模型内容
(1)删除此数据库
(2)再重建此数据库
(3)删除迁移文件(firstapp/migrations目录下0001_initial.py文件)
(4)执行迁移文件(project目录下输入python manage.py makemigrations)
(5)再迁移(project目录下输入python manage.py migrate)

添加班级数据

mysql> select *from grades;                      >3;
+----+------------+----------------------------+------+----------+
| id | gname      | gdate                      | gnum | isDelete |
+----+------------+----------------------------+------+----------+
|  1 | 计算机一班 | 2012-02-04 00:00:00.000000 |   30 |        0 |
|  2 | 计算机二班 | 2012-02-04 00:00:00.000000 |   30 |        0 |
|  3 | 财务管理   | 2012-02-04 00:00:00.000000 |   30 |        0 |
|  4 | 市场营销   | 2012-02-04 00:00:00.000000 |   30 |        0 |
+----+------------+----------------------------+------+----------+

添加学生数据

mysql> select *from students;
+----+--------+---------+------+------------+----------+-----------+
| id | sname  | sgender | sage | scontend   | isDelete | sgrade_id |
+----+--------+---------+------+------------+----------+-----------+
|  1 | 薛艳梅 |       0 |   20 | 我叫薛艳梅 |        0 |         1 |
|  2 | 向方   |       0 |   21 | 我叫向方   |        0 |         1 |
|  3 | 孔雨   |       1 |   21 | 我叫孔雨   |        0 |         2 |
|  4 | 孟林   |       1 |   20 | 我叫孟林   |        0 |         3 |
|  5 | 夏明   |       1 |   20 | 我叫夏明   |        0 |         2 |
|  6 | 孙艳   |       0 |   19 | 我叫孙艳   |        0 |         3 |
|  7 | 田宝   |       1 |   20 | 我叫田宝   |        0 |         4 |
+----+--------+---------+------+------------+----------+-----------+

4、元选项

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

把之前的firstapp_grades改成grades,firstapp_students改成students

  • db_table 定义数据表名,推荐使用小写字母,数据表明默认
    “项目名小写_类名小写”(如db_table=“students”)
  • ordering=[] 对象的默认排序字段,或许对象的列表时使用
    ordering=[“id”] ------- 升序
    ordering=[“-id”] ------- 降序
    注意:排序会增加数据库的开销
#在班级类最后添下面两条代码,会把之前的firstapp_grades改成grades
class Meta:
    db_table="grades"
#在学生类最后添下面两条代码,会把之前的firstapp_students改成students
class Meta:
    db_table="students"
    ordering=["id"]        
    

具体如下图:
在这里插入图片描述
在数据库中数据表名显示出来,如下图
在这里插入图片描述

六、模型成员

1、类属性

sname,sgender,sage,scontend等等都是类属性

(1)objects

  • objects---->是Manager类型的一个对象,作用是与数据库进行交互
  • 当定义模型类没有指定管理器,则django为模型创建一个名为objects的管理器
>>> from firstapp.models import Students
>>> stu=Students.objects.get(pk=1)
>>> stu
<Students: 薛艳梅>
>>> stu.sage=22
>>> stu.save()
mysql> select *from students;
+----+--------+---------+------+------------+----------+-----------+
| id | sname  | sgender | sage | scontend   | isDelete | sgrade_id |
+----+--------+---------+------+------------+----------+-----------+
|  1 | 薛艳梅 |       0 |   22 | 我叫薛艳梅 |        0 |         1 |
|  2 | 向方   |       0 |   21 | 我叫向方   |        0 |         1 |
|  3 | 孔雨   |       1 |   21 | 我叫孔雨   |        0 |         2 |
|  4 | 孟林   |       1 |   20 | 我叫孟林   |        0 |         3 |
|  5 | 夏明   |       1 |   20 | 我叫夏明   |        0 |         2 |
|  6 | 孙艳   |       0 |   19 | 我叫孙艳   |        0 |         3 |
|  7 | 田宝   |       1 |   20 | 我叫田宝   |        0 |         4 |
+----+--------+---------+------+------------+----------+-----------+

(2)自定义模型管理器

当我们为模型指定模型管理器,django就不再为模型类生成objects模型管理器

class Grades(models.Model):
    #自定义模型管理器
    #当自定义模型管理器时,objects就不存在了
    stuObj=models.Manager()
>>> from firstapp.models import Students
>>> stu=Students.stuObj.get(pk=1)
>>> stu
<Students: 薛艳梅>
>>> stu.sage=22
>>> stu.save()

(3)自定义模型管理器Manager类

  • 模型管理器时django的模型进行与数据库进行交互的接口,一个模型类可以有多个模型管理器
  • 作用
    (1)可以向管理器类中添加额外的方法
    (2)修改管理器返回的原始查询集
    重写get_queryset()方法,比如可以过滤掉已经删除的学生,薛艳梅显示已删除,isDelete为1
>>> stu=Students.objects.all()
>>> stu
#下面的统称查询集,数据库中所有都拿出来,并没有进行过滤
<QuerySet [<Students: 薛艳梅>, <Students: 向方>, <Students: 孔雨>, <Students: 孟林>, <Students: 夏明>, <Students: 孙艳>, <Students: 田宝>]>
class StudentsManager(models.Manager):
    def get_queryset(self):
        return super(StudentsManager,self).get_queryset().filter(isDelete=False)
class Students(models.Model):
    #自定义模型管理器
    #当自定义模型管理器时,objects就不存在了
    stuObj=models.Manager()
    stuObj2=StudentsManager()

在这里插入图片描述

#自定义模型管理器,objects就不存在了
>>> stu=Students.objects.all()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: type object 'Students' has no attribute 'objects'
>>> stu=Students.stuObj.all()
>>> stu
#下面的统称查询集,数据库中所有都拿出来,并没有进行过滤
<QuerySet [<Students: 薛艳梅>, <Students: 向方>, <Students: 孔雨>, <Students: 孟林>, <Students: 夏明>, <Students: 孙艳>, <Students: 田宝>]>
>>> stu=Students.stuObj2.all()
>>> stu
#stuObj2则过滤掉已经删除的学生,薛艳梅显示已删除,isDelete为1
<QuerySet [<Students: 向方>, <Students: 孔雨>, <Students: 孟林>, <Students: 夏明>, <Students: 孙艳>, <Students: 田宝>]>

2、创建对象

(1)目的:

向数据库中添加数据

(2)当创建对象时,django不会对数据库进行读写操作,当调用save()方式时才与数据库进行交互,将对象保存在数据库表中

(3)注意:

__ init__.py方法已经在父类models.Model中使用,在自定义的模型中是无法使用

(4)方法

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

#在学生类下定义下面类方法,注意使用@classmethod
#定义一个类方法创建对象,装饰器表明下面的定义的是类方法
@classmethod
def createStudent(cls,name,gender,age,contend,grade,isD=False):
    stu = cls(sname=name,sgender=gender,sage=age,scontend=contend,isDelete=isD,sgrade=grade)
    return stu

在这里插入图片描述
在views.py最下面添加

from .models import Students,Grades
def addstudent(request):
    grade=Grades.objects.get(pk=1)
    stu =Students.createStudent("刘美美",0,34,"我叫刘美美",grade)
    stu.save()
    return HttpResponse('avnjka')

在firstapp.py/urls.py文件下添加路径

path('addstudent/',views.addstudent)

输入网址http://localhost:8000/firstapp/addstudent/
得到下图,表示models.py中数据添加成功
在这里插入图片描述

2)在自定义管理器中自定义一个方法,正好应对属性类中自定义管理器Manager类,可以排除掉已经删除了的学生

class StudentsManager(models.Manager):
    def get_queryset(self):
        return super(StudentsManager,self).get_queryset().filter(isDelete=False)
    def createStudent(self,name,gender,age,contend,grade,isD=False):
        stu=self.model()
        stu.sname=name
        stu.sgender=gender
        stu.sage=age
        stu.scontend=contend
        stu.sgrade=grade
        return stu

在这里插入图片描述

在views.py最下面添加

def addstudent2(request):
    grade=Grades.objects.get(pk=1)
    stu =Students.stuObj2.createStudent("刘梅",0,34,"我叫刘梅",grade)
    stu.save()
    return HttpResponse('********')

在firstapp.py/urls.py文件下添加路径

path('addstudent2/',views.addstudent2)

在网页http://localhost:8000/firstapp/addstudent2/
得到如下图,证明学生信息添加成功
在这里插入图片描述

七、模型查询

1、概述

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

2、查询集

下面是返回所有查询集

return super(StudentsManager,self).get_queryset()

(1)在管理器上调用过滤器方法返回查询集

class StudentsManager(models.Manager):
    def get_queryset(self):
        return super(StudentsManager,self).get_queryset().filter(isDelete=False)

(2)查询集经过过滤器筛选后返回新的查询集,所以我们可以写成链式调用

super(StudentsManager,self).get_queryset().filter(isDelete=False).filter()...#还可以往后再写

(3)惰性执行-------创建查询集不会带来任何数据的访问,直到调用数据时,才会访问数据库(也是为了提高性能)

(4)直接访问数据的情况

  • 迭代
  • 序列化
  • 与if合用

(5)返回查询集的方法称为过滤器(返回多条数据)

  • all()返回查询集中的所有数据

  • filter(),返回符合条件的数据
    (1)filter(键=值)
    (2)filter(键=值,键=值) (两个键值对是且的关系)
    (3)filter(键=值).filter(键=值)

  • exclude() 返回不符合条件的数据

  • order_by() 排序

  • values() 一条数据就是一个对象(字典),返回一个列表,

(6)返回单个数据

  • get ()----- 返回一个满足条件的对象
    注意:(1)如果没有找到符合条件的对象,会引发“模型类.DoesNotExist”异常
    (2)如果找到多个对象,会引发“模型类.MultipleObjectsReturned”异常
    比如在views.py中studentsList=Students.stuObj2.get(sgender=True),性别都为男,对象很多
  • count()-----返回当前查询集中的个数Grades.objects.count()
  • first()-----返回查询集中的第一个对象
  • last()------返回查询集中的最后一个对象
  • exists()----判断查询集中是否有数据,如果有数据,返回True
    Grades.objects. exists()

(7)限制查询集–查询集返回列表,可以使用下标的方法,进行限制等同于sql中的limit语句,

studentsList=Students.stuObj2.all()[0:5]#取五行数据,在views.py中添加
注意:下标不能是负数
1、在firstapp/views.py文件下,添加下面这些数据

from .models import Students,Grades
#分页显示学生
def stupage(request,page):
    #0-3  3-6  6-9
    #1      2    3
    #page*3
    page=int(page)
    studentsList=Students.stuObj2.all()[(page-1)*3:page*3]
    return render(request,'firstapp/students.html',{"students":studentsList})

在这里插入图片描述
2、在firstapp/urls.py文件下,添加下面代码

path('stu/<int:page>',views.stupage),

在这里插入图片描述
3、输入网址在http://localhost:8000/firstapp/stu/1
在这里插入图片描述
4、输入网址在http://localhost:8000/firstapp/stu/2
在这里插入图片描述
5、输入网址在http://localhost:8000/firstapp/stu/3
在这里插入图片描述

(8)查询集的缓存

概述

  • 每个查询集都包含一个缓存,来最小化的对数据库访问
  • 在新建的查询集中,缓存首次为空,第一次对查询集求值(访问数据),会发生数据缓存,django会将查询出来的数据做一个缓存,并返回查询结果,以后的查询直接使用查询集的缓存

(9)字段查询–参数

1、概念

  • 实现了sql中的where语句,作为方法filter(),exclude(),get()的参数
  • 语法:属性名__比较运算符=值(模型类中对应的属性)(比如:sage__>=20年龄大于20的)
  • 外键:属性名_id(如:sgrade_id
  • 转义:sql中的like语句中使用%是为了匹配占位,匹配数据中的%(where like “%”)(模糊查询)
    在过滤器中使用filter(sname__contains="%")

2、比较运算符

  • (1)exact----判断,区分大小写,类似filter(isDelete=False)
  • (2)contains----是否包含,区分大小写,filter(sname__contains=“刘”)
#在firstapp/views.py文件下添加下面这些代码
from .models import Students,Grades
def studentsearch(request):
#显示名字里面含有刘字的学生信息
    studentsList=Students.stuObj2.filter(sname__contains="刘")
    return render(request,'firstapp/students.html',{"students":studentsList})

在firstapp/urls.py文件下添加

path('studentsearch/',views.studentsearch),

输入http://localhost:8000/firstapp/studentsearch/网址,显示名字里面含有刘字的学生信息
在这里插入图片描述

  • (3)startswith、endswith----以value开头或者结尾,区分大小写,filter(sname__startswith=“田”)
#在firstapp/views.py文件下
from .models import Students,Grades
def studentsearch2(request)#显示名字里面以田字开头的学生信息
    studentsList=Students.stuObj2.filter(sname__startswith="田")
    return render(request,'firstapp/students.html',{"students":studentsList})

在firstapp/urls.py文件下添加

 path('studentsearch2/',views.studentsearch2),

输入http://localhost:8000/firstapp/studentsearch2/网址,显示名字里面以田字开头的学生信息
在这里插入图片描述

  • (4)以上四个在前面加上i,就表示不区分大小写,iexact、icontains、istartswith、iendswith
  • (5)isnull、isnotnull ----是否为空,filter(sname__isnull=False)
  • (6) in -----是否包含在范围内
#在firstapp/views.py文件下
from .models import Students,Grades
def studentsearch3(request):
    #获取pk在2,4,6里面的学生信息
    studentsList=Students.stuObj2.filter(pk__in=[2,4,6])
    return render(request,'firstapp/students.html',{"students":studentsList})

在firstapp/urls.py文件下添加

path('studentsearch3/',views.studentsearch3),

输入http://localhost:8000/firstapp/studentsearch3/
在这里插入图片描述

  • (7)gt----大于、gte----大于等于、lt----小于、lte----小于等于
#年龄大于20的学生信息,只有下面部分替换,其余部分类似
studentsList=Students.stuObj2.filter(sage__gt=20)
  • (8)year、month、day、week_day、hour、minute、second
#创建时间是2020的班级信息
gradesList=Grades.objects.filter(gdate__year=2020)
  • (9)跨关联查询
    处理join查询----语法:模型类名__属性名__比较运算符
def grades(request):
    #描述中带有'刘美美'这三个字的数据是属于哪个班级的 
    gradesList=Grades.objects.filter(students__scontend__contains='刘美美')
    return render(request,'firstapp/grades.html',{"grades":gradesList})
  • (10)查询快捷----pk----代表的主键

3、聚合函数
想用哪个聚合函数需要引用

#五个里面,用哪个引用哪个
from django.db.models import Avg,Count,Max,Min,Sum
  • 使用aggregate( )函数,返回聚合函数的值
  • (1)Avg----平均值
  • (2)Count----和
  • (3)Max----maxAge=Students.stuObj2.aggregate(Max('sage'))
  • (4)Min
  • (5)Sum

4、F对象

  • 可以使用模型的A属性与B属性进行比较,比如某个班级男生人数(A)和女生人数(B)进行比较filter(ggirlnum__gt=F('gboynum'))
  • 支持F对象的算数运算filter(ggirlnum__gt=F('gboynum')+20)

需要引入F,Q
(1)

from django.db.models import F,Q
def grades1(request):
    #查看女生人数大于男生人数的班级,需要在models.py文件里面,班级下面,添加ggirlnum,gboynum这两个属性
    g=Grades.objects.filter(ggirlnum__gt=F('gboynum'))
    print(g)
    return HttpResponse("oooooo")

(2)

from django.db.models import F,Q
def grades1(request):
    #查看(女生人数)大于(男生人数+20)的班级,需要在models.py文件里面,班级下面,添加ggirlnum,gboynum这两个属性
    g=Grades.objects.filter(ggirlnum__gt=F('gboynum')+20)
    print(g)
    return HttpResponse("oooooo")

5、Q对象

  • 概述:过滤器的方法中的关键字参数,条件为And模式
  • 需求:进行or查询
  • 解决:使用Q对象
  • studentsList=Students.stuObj2.filter(Q(pk__lte=2))----只有一个Q就是用于匹配的
  • studentsList=Students.stuObj2.filter(~Q(pk__lte=2))----取反
from django.db.models import F,Q
def students(request):
    #pk<2或者年龄大于23  的学生信息
    studentsList=Students.stuObj2.filter(Q(pk__lte=2) | Q(sage__gt=23))
    return render(request,'firstapp/students.html',{"students":studentsList})
原文地址:https://www.cnblogs.com/llb123/p/13398716.html