zoukankan      html  css  js  c++  java
  • 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})
    
  • 相关阅读:
    2017.7.14 使用case when和group by将多条数据合并成一行,并且根据某些列的合并值做条件判断来生成最终值
    2017.7.12 IDEA热部署(更新jsp或java代码不用重启tomcat即可即时生效)
    2017.7.10 Package name does not correspond to the file path
    2017.7.10 Redis报错:DENIED Redis is running in protected mode
    2017.7.10 (windows)redis的安装
    2017.7.7 postgreSQL在插入造成重复时执行更新
    2017.7.1 nginx反向代理服务器域名解析配置(已验证可使用)
    2017.7.1 ftp文件服务器安装与配置(已验证可使用)
    2017.7.1 mysql安装与启动(已验证可以使用)
    日期格式,拼接、跳转,字符集转码(中文乱码)
  • 原文地址:https://www.cnblogs.com/llb123/p/13398716.html
Copyright © 2011-2022 走看看