日志一我们学习了Django的配置,详见:
Django学习日志一Django的配置
日志二我们学习了创建第一个django项目,详见:
Django学习日志二——创建第一个django项目
下面我们来学习模型层的使用:
模型层用于和数据交互。可以通过模型和关系型数据库实现持久化的操作。在Django开发中主要以MySQL作为首选数据库,同时使用非关系型数据库MongoDB存储日志、记录历史信息等数据。
Django中默认使用SQLite数据库,在开发中如果需要使用MySQL关系型数据库,就需要进行额外配置。步骤如下:
修改./hello/setting.py中的DATABASES参数
原文件如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
修改后如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'hello',
'USER': 'root', # mysql账户名
'PASSWORD': '123456', # mysql密码
'Host': '127.0.0.1',
'PORT': 3306,
}
}
ENGINE参数:表示数据库的引擎
NAME参数:表示访问MYSQL中的数据库的名称
USER参数:表示访问MYSQL的用户名
PASSWORD参数:表示访问MYSQL的密码
HOST参数:表示访问IP数据库的地址(如果访问本地数据库,可以写为localhost或者127.0.0.1)
PORT参数:表示数据库的端口(端口是3306)
配置数据库
由于Django连接MYSQL时默认使用MYSQLdb驱动,然而Python3并不支持MYSQLdb驱动,只能安装pymysql包连接MySQL数据库
pip install pymysql
PyMySQL的初始化配置
在_init_.py中实现PyMySQL的初始化配置:
import pymysql
pymysql.install_as_MySQLdb()
[示例]在hello/app/models.py文件中,定义一个模型类Student,并定义数据表名student
from django.db import models
class Student(models.Model): # Student继承models.Model类
s_name = models.CharField(max_length=10, unique=True)
s_age = models.IntegerField(default=16)
s_sex = models.BooleanField(default=1)
operator_time = models.DateTimeField(auto_now=True)
create_time = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'student'
注意:由于Student继承models.Model类,而models类中定义了自增的id,因此在Student模型中相当于定义了6个字段:
在模型中还定义了嵌套类Meta,用于向Django说明关于此模型的各种元数据信息,如数据表名称,以及查询数据表时默认排序规则等
Django中模型字段 | 定义说明 |
---|---|
AutoField | 一个根据实际id自动增长的IntegerField,通常不指定。不指定时主键字段自动添加到模型中 |
CharField = (max_length=字符长度) | 字符串,参数说明:max_length=字符长度 |
TextField | 大文本字段,一般超过4000字符时使用,默认的表单控件是Textarea |
IntegerField | 整数 |
DecimalField =(max_digits=None,decimal_places=None) | 使用Python的Decimal实例表示的十进制浮点数。参数说明:max_digits=位数总数,decimal_places=小数点后面的数字位数 |
BooleanField | True/False字段,此字段的默认表单控件是CheckboxInput |
NullBooleanField | 支持null、True、False这3种值 |
DataField = ([auto_now=False,auto_now_add=False]) | 使用Python的datatime.data实例表示的日期。参数说明:auto_now表示每次保存对象时自动设置该字段为当前时间;auto_now_add表示当对象第一次被创建时自动设置当前时间。auto_now、auto_now_add这两个参数设置是相互排斥的。 |
TimeField | 使用Python的datatime.data实例表示的时间,参数同DataField |
DataTimeField | 使用Python的datatime.data实例表示的日期和时间,参数同DataField |
FileField | 一个上传文件的字段 |
ImageField | 继承了FileField的所有属性和方法,但对上传的对象会进行校验,确保它是有效的image |
字段的约束条件 | 作用 |
---|---|
null | 如果为True,则该字段在数据库中是空数据。默认值是False |
blank | 如果为True,则该字段允许为空白,默认值是False |
db_column | 字段的名称,如果未指定,则使用该字段属性的名称 |
db_index | 如果为True,则在表中为此字段创建索引 |
default | 默认值 |
primary_key | 如果为True,则该字段会成为模型的主要字段 |
unique | 如果为True,则这个字段在表中必须有唯一值 |
在Django中可以通过数据库迁移命令,将models.py定义的数据模型映射到数据库中,并生成对应的数据表。
步骤一:
在Terminal控制台切换到hello\中输入:
python manage.py makemigrations
(django2.0.7) E:\python save\django\hello>python manage.py makemigrations
Migrations for 'app':
app\migrations\0001_initial.py
- Create model Student
此时在app文件夹下的migration文件夹中自动创建了一个0001_initial.py文件。再次执行migrations,会将models.py中的模型与已有数据库对比,如果有差异,则会再次生成类似0001_initial.py的迁移文件。如果没有差异,则不会进行任何操作。
(django2.0.7) E:\python save\django\hello>python manage.py makemigrations
No changes detected
步骤二:
在Terminal控制台切换到hello\中输入:
(django2.0.7) E:\python save\django\hello>python manage.py migrate
...
这样就将makemigrations命令生成的迁移数据库脚本同步到本地数据库中。在第一次使用python manage.py migrate命令时,数据库会自动创建Django中使用的默认数据表,例如,用户表(auth_user)、权限表(auth_permission)等。
注意:本节可以先快速浏览一遍,理解相关MySQL操作即可。今后使用时按照需求写代码。
查询学生模型中的数据,有以下方法:
all():查询模型中的所有数据,并返回查询集中的QuerySet结果集。
filter():返回一个符合查询条件的QuerySet结果集。
get():返回一个符合条件的Student Object结果集。注意,如果没有满足条件的结果集会抛出异常;如果查询的结果超过一个也会抛出异常。
exclude():返回不符合条件的QuerySet结果集,和filter()相反。
first():查询QuerySet结果集中的第一个对象。
last():查询QuerySet结果集中的最后一个对象。
order_by():按照某个字段升序或者降序进行排序。
# 查询学生表中所有的数据,all()的使用
stus=Student.objects.all()
# 查询年龄等于15的学生,filter()的使用
stus=Student.objects.filter(s_age=15)
# 查询年龄不等于15的学生,exclude()的使用
stus=Student.objects.exclude(s_age=15)
# 查询id为1的学生信息
stus=Student.objects.filter(id=1)
stus=Student.objects.get(id=1)
stus=Student.objects.get(pk=1) # 查询时主键id可用pk代替
# 获取所有学生(按照id降序)中第一个学生的信息
stus=Student.objects.all().order_by('-id')[0]
stus=Student.objects.all().order_by('-id').first()
# 获取所有学生(按照id降序)中最后一个学生的信息
stus=Student.objects.all().order_by('-id').last()
# 第一种,获取学生模型对象,给对象属性赋值,并使用save()方法保存
stu = Student()
stu.s_name='王大锤'
stu.s_age=28
stu.yuwen=80
stu.shuxue=90
# 第二种,在学生模型中定义__init__(self,属性值,属性值,属性值,...)方法直接初始化对象,并使用save()方法保存
stu = Student('王大锤',28,80,90)
# 第三种,create()方法
Student.objects.create(s_name='王大锤',s_age=28,yuwen=80,shuxue=90)
# 第一种,获取学生模型对象,给对象属性赋值,并使用save()保存
stu=Student.objects.filter(id=2).first()
stu.s_name='小明明'
# 第二种,update()方法
Student.objects.filter(id=2).update(s_name='小明明')
# 删除数据
Student.objects.filter(id=3).delete()
一对一关系
在模型中可以使用OneToOneField来定义关联关系,它会接受一个参数,这个参数即要关联的模型类。
from django.db import models
class Student(models.Model):
s_name = models.CharField(max_length=10, unique=True)
s_age = models.IntegerField(default=16)
s_sex = models.BooleanField(default=1)
operator_time = models.DateTimeField(auto_now=True)
create_time = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'student'
class StudentInfo(models.Model):
address=models.CharField(max_length=20,null=True)
phone=models.IntegerField()
#################################
stu=models.OneToOneField(Student)
#################################
class Meta:
db_table='student_info'
在上面的例子中,如果想通过id=1的学生查找学生拓展表中该对象对应的电话号码,代码如下:
# 通过学生对象找一对一关联的表信息
stu=student.objects.get(pk=1)
student=stu.studentinfo
# 查找电话
phone=student.phone
如果已知电话号码,想通过电话号码查找学生的姓名等信息,代码如下:
# 通过拓展表找学生信息,知道电话号码12345678找学生
stuinfo=StudentInfo.objects.get(phone='12345678')
stu=stuinfo.stu
# 查找学生姓名
name=stu.s_name
一对多关系
在一个班级中有多个学生,那么班级是"一"的对象,学生是"多"的对象,班级和学生是一对多的关系。一对多使用ForeignKey来定义关联关系
from django.db import models
# 定义班级模型
class Grade(models.Model):
g_name=models.CharField(max_length=10)
class Meta:
db_table='grade'
# 定义学生模型
class Student(models.Model):
s_name = models.CharField(max_length=10, unique=True)
s_age = models.IntegerField(default=16)
s_sex = models.BooleanField(default=1)
operator_time = models.DateTimeField(auto_now=True)
create_time = models.DateTimeField(auto_now_add=True)
##########################
g=models.ForeignKey(Grade)
##########################
class Meta:
db_table = 'student'
提示:定义一对多关联关系的时候,使用ForeignKey()来定义外键,ForeignKey()定义的字段在"多"的一方。
如果已知班级和学生模型时,可以进行以下方式的查询:
已知学生id=4,查询该学生的班级信息。
# 查询id=4的学生的班级名称
stu=Student.object.get(id=4)
grade=stu.g
# 班级名称
name=grade.g_name
已知班级id=1,查询该班级下所有的学生信息
# 查询id=1的班级的所有学生
grade=Grade.objects.filter(id=1).first()
stus=grade.student_set.all()
student_set属性,该属性字段是Django设定的通过"一"找"多"的属性字段,返回一个QuerrySet结果集。
如果在外键中设置related_name参数,即修改外键定义为g=models.ForeignKey(Grade,related_name=‘students’),则可以通过下面的方式查询该班级下所有学生信息:
使用related_name查询班级对应的学生信息
# 查询id=1的班级的所有学生
grade=Grade.objects.filter(id=1).first()
stus=grade.students.all()
多对多关系
一个学生可以选择多门课程,一个课程也可以被多个学生选择,那么学生和课程就是一组多对多的关系。在Django中由ManyToManyField字段来表示多对多的关联关系。示例代码如下:
from django.db import models
# 学生模型
class Student(models.Model):
s_name = models.CharField(max_length=10, unique=True)
s_age = models.IntegerField(default=16)
s_sex = models.BooleanField(default=1)
operator_time = models.DateTimeField(auto_now=True)
create_time = models.DateTimeField(auto_now_add=True)
g = models.ForeignKey(Grade)
class Meta:
db_table = 'student'
# 课程模型
class Course(models.Model):
c_name=models.CharField(max_length=10)
stu=models.ManyToManyField(Student)
class Meta:
db_table = 'course'
注意:在两种模型中的任一个模型中都可以定义字段,因为多对多的关联关系是对称的。
在使用数据库迁移命令后,会发现数据库中创建了一张student学生表、一张course表,以及一张课程表和学生对应的中间表,该中间表中的两个外键分别关联到学生表主键和课程表主键。
中间表在Django ORM的使用过程中通常处于隐藏状态,不可以直接对中间表进行查询。
关于学生查找、添加和删除课程的操作,有如下代码:
给id=4的学生添加两门课程,课程id分别为1和2
# id=4的学生添加两门课程(id=1,2)
stu = Student.objects.get(id=4)
c1 = Course.object.get(id=1)
c2 = Course.object.get(id=2)
stu.course_set.add(c1)
stu.course_set.add(c2)
删除某个学生的某个课程
# 删除id=4的学生的课程中id=1的课程
stu = Student.objects.get(id=4)
stu.course_set.remove(c1)
查询某个学生的所有课程
stu=Student.objects.get(id=4)
# 查询学生的所有课程
courses=stu.course_set.all()
本日志所有内容学习自《Python Web开发从入门到精通》(王海飞编著)、网络资源以及本人的调试 ↩︎