Django学习日志三:模型层
日志一我们学习了Django的配置,详见: Django学习日志一Django的配置 日志二我们学习了创建第一个django项目,详见: Django学习日志二——创建第一个django项目
下面我们来学习模型层的使用:
五、模型层
模型层用于和数据交互。可以通过模型和关系型数据库实现持久化的操作。在Django开发中主要以MySQL作为首选数据库,同时使用非关系型数据库MongoDB存储日志、记录历史信息等数据。
5.1配置数据库MySQL
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',
'PASSWORD': '123456',
'Host': '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()
5.2 创建模型,字段类型约束说明
[示例]在hello/app/models.py文件中,定义一个模型类Student,并定义数据表名student
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'
注意:由于Student继承models.Model类,而models类中定义了自增的id,因此在Student模型中相当于定义了6个字段:
- id——自增的主键
- s_name——学生姓名
- s_age——学生年龄
- s_sex——学生性别
- operator_time——操作时间
- create_time——创建时间
在模型中还定义了嵌套类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,则这个字段在表中必须有唯一值 | | |
5.3 数据库迁移
在Django中可以通过数据库迁移命令,将models.py定义的数据模型映射到数据库中,并生成对应的数据表。
- makemigrations命令是将models中定义的数据模型转换为数据库脚本
- migrate命令是执行该数据库脚本
步骤一:
在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)等。
5.4 ORM编程
注意:本节可以先快速浏览一遍,理解相关MySQL操作即可。今后使用时按照需求写代码。
- 查询语法
查询学生模型中的数据,有以下方法:
-
all():查询模型中的所有数据,并返回查询集中的QuerySet结果集。 -
filter():返回一个符合查询条件的QuerySet结果集。 -
get():返回一个符合条件的Student Object结果集。注意,如果没有满足条件的结果集会抛出异常;如果查询的结果超过一个也会抛出异常。 -
exclude():返回不符合条件的QuerySet结果集,和filter()相反。 -
first():查询QuerySet结果集中的第一个对象。 -
last():查询QuerySet结果集中的最后一个对象。 -
order_by():按照某个字段升序或者降序进行排序。
stus=Student.objects.all()
stus=Student.objects.filter(s_age=15)
stus=Student.objects.exclude(s_age=15)
stus=Student.objects.filter(id=1)
stus=Student.objects.get(id=1)
stus=Student.objects.get(pk=1)
stus=Student.objects.all().order_by('-id')[0]
stus=Student.objects.all().order_by('-id').first()
stus=Student.objects.all().order_by('-id').last()
- 新增语法
stu = Student()
stu.s_name='王大锤'
stu.s_age=28
stu.yuwen=80
stu.shuxue=90
stu = Student('王大锤',28,80,90)
Student.objects.create(s_name='王大锤',s_age=28,yuwen=80,shuxue=90)
- 修改语法
stu=Student.objects.filter(id=2).first()
stu.s_name='小明明'
Student.objects.filter(id=2).update(s_name='小明明')
- 删除语法
Student.objects.filter(id=3).delete()
5.5 模型关联
-
一对一关系 在模型中可以使用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
如果已知电话号码,想通过电话号码查找学生的姓名等信息,代码如下:
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,查询该学生的班级信息。
stu=Student.object.get(id=4)
grade=stu.g
name=grade.g_name
-
已知班级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查询班级对应的学生信息
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
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)
-
删除某个学生的某个课程
stu = Student.objects.get(id=4)
stu.course_set.remove(c1)
-
查询某个学生的所有课程 stu=Student.objects.get(id=4)
courses=stu.course_set.all()
|