Django学习日志三:模型层

Django学习日志三:模型层1

日志一我们学习了Django的配置,详见:
Django学习日志一Django的配置
日志二我们学习了创建第一个django项目,详见:
Django学习日志二——创建第一个django项目

下面我们来学习模型层的使用:

五、模型层

模型层用于和数据交互。可以通过模型和关系型数据库实现持久化的操作。在Django开发中主要以MySQL作为首选数据库,同时使用非关系型数据库MongoDB存储日志、记录历史信息等数据。

5.1配置数据库MySQL

Django中默认使用SQLite数据库,在开发中如果需要使用MySQL关系型数据库,就需要进行额外配置。步骤如下:

  1. 修改./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)

  1. 配置数据库

    由于Django连接MYSQL时默认使用MYSQLdb驱动,然而Python3并不支持MYSQLdb驱动,只能安装pymysql包连接MySQL数据库
    pip install pymysql

  2. 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):	# 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个字段:

  1. id——自增的主键
  2. s_name——学生姓名
  3. s_age——学生年龄
  4. s_sex——学生性别
  5. operator_time——操作时间
  6. 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定义的数据模型映射到数据库中,并生成对应的数据表。

  1. makemigrations命令是将models中定义的数据模型转换为数据库脚本
  2. 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操作即可。今后使用时按照需求写代码。

  1. 查询语法

查询学生模型中的数据,有以下方法:

  • 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()
  1. 新增语法
# 第一种,获取学生模型对象,给对象属性赋值,并使用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)
  1. 修改语法
# 第一种,获取学生模型对象,给对象属性赋值,并使用save()保存
stu=Student.objects.filter(id=2).first()
stu.s_name='小明明'
# 第二种,update()方法
Student.objects.filter(id=2).update(s_name='小明明')
  1. 删除语法
# 删除数据
Student.objects.filter(id=3).delete()

5.5 模型关联

  1. 一对一关系

    在模型中可以使用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
    
  2. 一对多关系

    在一个班级中有多个学生,那么班级是"一"的对象,学生是"多"的对象,班级和学生是一对多的关系。一对多使用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()
      
  3. 多对多关系

    一个学生可以选择多门课程,一个课程也可以被多个学生选择,那么学生和课程就是一组多对多的关系。在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()
      

  1. 本日志所有内容学习自《Python Web开发从入门到精通》(王海飞编著)、网络资源以及本人的调试 ↩︎

你可能感兴趣的:(python,后端,django入门,django,学习,python)