创建一个Django工程及app
PS D:\test> django-admin startproject modelExplore
PS D:\test> cd modelExplore
PS D:\test\modelExplore> python manage.py startapp modelExample
PS D:\test\modelExplore>
添加app 到settings.py文件中的INSTALLED_APPS配置项中
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'modelExample',
]
配置数据库
使用默认的数据库:sqlite3
数据库的配置方法我在 [Django介绍与框架整合,并使用MySQL实现增删改查] 这篇文章中有过介绍。
模型
Django为了对各种数据库提供支持,因此抽象出一种模型的概念,并提供一套统一的调用API。这样你就可以根据业务需求去选择数据库,而不需要面对因数据库的变更而修改代码,极大地减轻了开发人员的工作量。
在学习模型前,我们先了解ORM(Object Relational Mapping:对象关系映射)的概念:
用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。简单理解,就是根据对象的类型生成表结构,将对象、列表操作转换为sql语句,将sql语句查询到的结果转换为对象、列表。
模型实现的就是一种对象关系映射,那么模型、属性、表、字段他们又有哪些不为人知的秘密呢?
- 一个模型类在数据库中对应一张表
- 在模型类中定义的属性对应模型对照表中的一个字段。
Django根据属性的类型确定以下信息。
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的默认html控件
- 在管理站点最低限度的验证
属性命名限制
- 不能是Python的保留关键字(遵循标识符规则)
- 由于Django的查询方式,不允许使用连续的下划线
定义模型
我们在modelExample这个目录下的models.py定义模型,定义模型需要引入django.db中的models,模型类要继承models.Model类,一个模型就是一个类。定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,为了方便使用,我们将整个django.db.models导入,我们以创建一个简单的用户表为例:
from django.db import models
# Create your models here.
class User(models.Model):
acocunt = models.CharField(max_length=20)
name = models.CharField(max_length=20)
passwd = models.CharField(max_length=16)
email = models.CharField(max_length=50)
sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
说明:不需要定义主键,在生成表时自动添加。
关系
分类:
- ForeignKey:一对多,将字段定义在多的端中
- ManyToOneField:多对多,将字段定义在两端中
- OneToOneField:一对一,将字段定义在任意一端中
用一访问多
- 格式:对象.模型类小写_set
- 示例:grade.students_set
用一访问一
- 格式:对象.模型类小写
- 示例:grade.students
访问id
- 格式:对象.属性_id
- 示例:student.sgrade_id
属性类型
- AutoField:一个根据实际ID自动增长的IntegerField,通常不指定,如果不指定一个主键字段将自动添加到模型中
Django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则Django不会再生成默认的主键列。
- CharField(max_length=字符长度):字符创,默认的表单样式是TextInput
- TextField:大文本字段,一般超过4000使用,默认的表单控件是Textarea
- IntegerField:整数
- DecimalField(max_digits=None, decimal_places=None):
使用Python的Decimal实例表示的十进制的浮点数 参数说明: DecimalField.max_digits:位数总数 DecimalField.decimal_places:小数点后的数字位数
- FloatField:用Python的float实例来表示的浮点数
- BooleanField:True/False字段,此字段的默认表单控制是CheckboxInput
- NullBooleanField:支持null.true,false三种字段
- DateField([auto_now=False,auto_now_add=False]):
使用Python的datetime.date实例表示的日期 参数说明: DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于“最后一次修改“的时间戳,他总是使用当前日期,默认为False DateField.auto_now_add:当前对象第一次被创建时设置当前时间,用于创建的时间戳,他总是使用当前日期,默认为False 说明: 该字段默认对应的表单控件是一个TextInput。在管理员站点添加了一个JavaScript写的日历控件,和一个Today的快捷按钮,包含了一个额外的invalid_date错误信息键 注意: Auto_now_add,auto_now and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果。
TimeField:使用Python的datetime.time实例表示的时间,参数同DateField
DateTimeField:使用Python的datetime,datetime实例表示的日期和时间,参数同DateField
FileField:一个上传文件的字段
ImageField:继承了FileField的所有属性和方法,但对上传的对象进行校验,确保他是个有效的image
外键ForeignKey
from django.db import models
class Grades(models.Model):
class_name = models.CharField(max_length=20)
headteacher = models.CharField(max_length=20)
students_count = models.IntegerField(2)
class student(models.Model):
student_num = models.CharField(max_length=20)
student_name = models.CharField(max_length=20)
student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
student_birth = models.DateField(auto_now_add=true)
student_grade = models.ForeignKey('Grades')
属性选项
- 通过属性选项,可以实现对属性的约束
- 在属性对象通过关键字参数指定
Null:如果为True,Django将控制以null存储到数据库中,默认值是False
-
Blank:如果为True,则该字段允许为空白,默认值是False
注意:null是数据库范畴的概念,blank是表单验证范畴的
Db_column:字段的名称,如果未指定,则使用属性的名称
Db_index:若值为True,则在表中会为此字段创建索引
Default:默认值
Primary_key:若为True,则该字段会成为模型的主键字段
Unique:如果为True,这个字段在表中必须有唯一值
元选项:在模型类定义中定义Meta类,用于设置元信息
Class Stucent(models.Model):
# someField
Class Meta:
db_table = 'stucents' # 定义数据表名,推荐使用小写字母,如果不写,数据表名默认为项目名小写_类名小写
ordering=['id'] # 对象的默认排序字段,获取对象的列表时使用。
# ordering = ['id']:升序;ordering = ['-id']:降序
# 注意:排序会增加数据库的开销。
生成迁移文件并执行迁移
在以往的开发模式中,我们通常都是设计好数据库表后,将其创建出来,然后通过sql来进行查询,而在Django中,我们可以省去数据库表的设计和创建步骤,我们定义模型其实就是对表的设计,执行迁移就是创建数据库表。修改模型后只需要再迁移即可
第一步:生成迁移文件
在我们的工程目录下执行以下命令:python manage.py makemigrations
PS D:\modelExplore> python manage.py makemigrations
Database version : 5.5.53
Migrations for 'firstApp': firstApp\migrations\0001_initial.py
- Create model User
PS D:\modelExplore>
如果控制台会打印出类似以上的内容,此时会在modelExample app目录下的migrations目录下生成一个迁移文件,但是现在还没有在数据库中创建表。
第二步:执行迁移
在执行完上一步后,只是生成了一个迁移文件,此时还没有在数据库中创建表,我们需要执行以下命令来生成数据表:python manage.py migrate
PS D:\modelExplore> python manage.py migrate
Database version : 5.5.53
Operations to perform: Apply all migrations: admin, auth, contenttypes, firstApp, sessions Running migrations:
Applying firstApp.0001_initial... OK
PS D:\modelExplore>
执行以上的命令相当于执行SQL语句创建了数据表。看到类似于上文的结果表示成功,可以去数据库中查看是否已经创建了这张表。表名是你的appName_modelName连接在一起的,当然了,表名也是可以自定义的(在元选项中有过说明)。
模型成员
类属性: objects,他是Manager类型的一个对象,作用是与数据库进行交互。当定义模型类时,没有指定管理器则Django默认为模型创建一个名为objects的管理器。
自定义模型管理器:
class student(models.Model):
stuObj = models.Manager() # 自定义模型管理器,此时再去使用objects就会报错了
student_num = models.CharField(max_length=20)
student_name = models.CharField(max_length=20)
student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
student_birth = models.DateField(auto_now_add=true)
student_grade = models.ForeignKey('Grades')
当模型指定模型管理器。Django就不在为模型类生成objects模型管理器了。模型管理器可以创建多个。
自定义管理器Manager类: 模型管理器是Django的模型进行与数据库进行交互的接口,一个模型类可以有多个模型管理器
作用:
- 向管理器中添加额外的方法
- 修改管理器返回的原始查询集----重写get_queryset()方法。
实例:
Class StudentsManager(models.Manager):
get_queryset(self):
return super(StudentsManager,self).getqueryset().filter(isDelete=False)
class student(models.Model):
# 为对象创建一个模型管理器
stuObj = objects_new = StudnetsManager()
student_num = models.CharField(max_length=20)
student_name = models.CharField(max_length=20)
student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
student_birth = models.DateField(auto_now_add=true)
student_grade = models.ForeignKey('Grades')
创建对象:
目的:向数据库中添加数据 当创建对象时,Django不会对数据库进行读写操作,当调用save()方法时才与数据库交互,将对象保存到数据库。
注意:__init__方法已经在基类(父类)中使用,在自定义的模型中无法使用
方法:
- 在模型类中增加一个类方法
- 在自定义管理器中添加一个方法
此处乱七八糟的呢
@classmethod
def createStudents(cls,name,age , gender, contend…):
student = cls(sname = name , sage = age…)
return student
stu.createStudents(…)
# 在自定义管理器中添加一个方法 在StudentsManager中创建一个方法
def createStudents(self,name,age , gender, contend…):
# 可以直接创建一个对象,但是这种方式不通用,限制了这个管理器。
stu = Students()
# 在通常情况下,我们使用以下的方法创建,这样什么对象调用就是什么对象
stu2 = self.model()
stu2.sname = name … Print(type(stu2))
student = cls(sname = name , sage = age…)
return student stu.obj.createStudents
# 定义一个类方法创建对象,此方法要创建在Students类中
模型查询
查询集:
查询集是表示从数据库中获取的对象的集合,查询集可以有多个过滤器,过滤器就是一个函数,基于所给的参数限制查询集结果。从sql角度来说,查询集合select语句等价,过滤器就像where条件。
1在管理器上调用过滤器方法返回结果集
2查询集经过过滤器筛选后返回新的查询集,所以我们可以写成链式调用
3惰性执行:创建查询集不会带来任何数据库的访问,直到调数据时,才会访问数据库
4直接访问数据的情况:
迭代:
序列化:
与if合用:
5返回查询集的方法称为过滤器
all():返回查询集中的所有数据
filter():返回符合条件的数据 :
filter(键=值);
filter(键=值,键=值);
filter(键=值).filter(键=值)
-
多条件是and查询
exclude():过滤掉符合条件的数据
order_by():排序
values():一条数据就是一个对象(字典),返回一个列表
6返回单个数据
get():返回一个满足条件的对象
注意:如果没有找到符合条件的对象,会引发‘模型类DoesNotExist’异常
如果找到了多个对象,也会引发‘模型类MultipleObjectsReturned’异常
count():返回当前查询集中的对象个数
first():返回当前查询集中的第一个对象
last():返回当前查询集中的最后一个对象
exists():判断查询集中是否有数据,如果有返回True,否则返回False
7限制查询集:查询集返回列表,可以使用下标的方法进行限制,等同于SQL中的limits
students.objects.all()[0:5]注意下标不能是负数
实现分页功能
8查询集的缓存
概述:每个查询集都包含一个缓存,来最小化的对数据库访问
在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存。,django会将查询出来的数据做缓存,并返回查询结构,以后的查询直接使用查询缓存的方式查询。
9字段查询
概述:
1实现了SQL中的where语句作为方法filter()、exclude()、get()的参数
2语法:属性名称比较运算符=值
3外键:属性名id
4转义:类似SQL中的like语句中使用%为了匹配占位。
例:filter(sname__contains=”%”)
比较运算符:
1exact判断,大小写敏感,例filter(isDelete=False)
2contailns:是否包含,大小写敏感:例:student.objects.filter(sname__contains=’于’)
3startswith/endswith:以value开头或结尾,大小写敏感
以上四个在前面加上一个I,就表示不区分大小写:iexact/icontains/istartswith
4isnull/isnotnull :是否为空;filter(sname__isnull=False)
5in : 是否包含。filter(pk__in=[2,4,6,8,])
6gt/gte/lt/lte : 大于/大于等于/小于/小于等于;filter(sage__gt=50)
7year/month/day/week_day/hour/minute/second : 日期 filter(last_time__year = 2018)
8跨关联查询:
处理join语句:
语法:模型类名属性名_比较运算符
# 描述中带有小白兔关键字的数据属于哪个班级
Grades.objects.filter(Students__scontend__contains=’小白兔’)
9快速查询:pk:代表的主键
聚合函数:使用aggregate()函数返回聚合函数的值
1Avg:
2Count
3Max/Min/Sum
from django.db.model import Max
Students.objects.aggregate(Max(‘sage’))
F对象:可以使用模型的A属性与B属性进行比较
from django.db.model import F
Grades.objects.filter(ggirlnum__gt=F(‘gboynum’) + 20)
支持F对象算数运算和时间运算
Q对象
概述:过滤器的方法中的关键字参数,条件为and方式
需求:进行or查询
解决:使用Q对象
from django.db.model import Q
Students.objects.filter(Q(pk__lt=3) | Q(sage__gt=50))
# 只有一个Q的时候,与没有Q相同
Students.objects.filter(Q(pk__lt=3))
# 在Q前加一个~,表示取反
Students.objects.filter(~Q(pk__lt=3))