接外包,有相关需求的可以联系我:Telegram | Email

Django-Models

该文章创建(更新)于05/29/2022,请注意文章的时效性!

模型

  • Django 对各种数据库提供了很好的支持,Django为这些数据库提供了统一的调用API,可以根据不同的业务需求选择不同的数据库。

  • 学习视频

ORM

  • 概述
    • 对象-映射-模型
  • 任务
    • 根据对象的类型生成表结构
    • 将对象、列表的操作转换为sql语句
    • 将SQL语句查询的结果转换为对象、列表
  • 优点
    • 极大的减轻了开发人员的工作量,不需要面对因数据库的变更而修改代码

流程

配置数据库

  • __init__.py文件中添加选定的数据库Package。
import pymysql  
pymysql.version_info = (2,0,3,"final",0)  
pymysql.install_as_MySQLdb()
  • settings.py文件中修改数据库配置。
DATABASES = {  
    'default': {  
        'ENGINE': 'django.db.backends.mysql',  
        'NAME': 'sunck', # 数据库名  
        'USER': 'sunk', # 数据库用户名  
        'PASSWORD': 'sunk', # 数据库密码  
        'HOST': 'localhost', # 数据库主机  
        'PORT': '3306', # 数据库端口  
    }  
}

在models.py 添加模型类

  • 一个模型类都在数据库中对应一张表

定义模型

模型、属性、表、字段间的关系

  • 一个模型类在数据库中对应一张表
  • 模型类中定义的属性,对应模型对照表中的字段

定义属性

概述

  • Django根据属性的类型确定以下信息
    • 当前选择的数据库支持字段的类型
    • 渲染管理表单时使用的默认html控件
    • 在管理站点最低限度的验证
  • Django会为表增加自动增加的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则Django不会再生成默认的主键列。
  • 属性命名限制
    • 不能是Python的保留关键字(遵循标识符命名规则)
    • 由于Django的查询方式,不允许使用连续的下划线

  • 定义属性时,需要字段类型,字段类型被定义再django.db.modles.fields目录下,为了方便使用,被导入到django.db.modles
  • 使用方式:
    • 导入from django.db import models
    • 通过modles.Field创建字段类型的对象,赋值给属性

逻辑删除

  • 对于重要数据都做逻辑删除 ,不能做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False

字段类型

字段类型 说明
AutoField 一个根据实际ID自动增长的IntergerField,通常不指定,如果不指定一个主键字段将自动添加到模型中
CharField(max_length=字符长度) 字符串,默认的表单样式是TextInput
TextField 大文本字段,一般超过4000字节使用,默认的表单控件是textArea
IntegerField 整数
DecimalFiled(max_digits=None,decimal_places=None) 使用Python的Decimal实例表示的十进制浮点数,max_digits表示位数总数,decimal_places表示小数点后的数字位数。[[精确的浮点运算-Decimal]]
FloatField 用Python的Float实例来表示的浮点数
BooleanField true/false字段,此字段的默认表单控制是CheckboxInput
NullBolleanField 支持null、true、false三种值
DateField([auto_now=False,auto_now_add=False]) 使用Python的Datetime.date实例表示的日期,auto_now表示每次保存对象是,自动设置该字段为当前时间,用于“最后一次修改”的时间戳,它总是使用当前日期,默认为False。auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前时间,默认为False。说明:该字段默认对于表单控件是一个TextField,在管理员站点添加了一个JavaScript写的日历控件,和一个“Today”的快捷按钮,包含了一个额外的invalid_date错误消息键。注意:auto_now_add、auto_now、defalut这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果。
TimeField 使用Python的datetime,datetime实例表示的日期和时间,参数同DateField
FiledField 一个上传文件的字段
ImageField 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是一个有效的image

字段选项(字段参数)

  • 概述:
    • 通过字段选项,可以实现对字段的约束
    • 在字段对象是通过关键字参数指定
  • null
    • 如果为True,Django将空值已NULL存储到数据库中,默认是False
  • blanke
    • 如果为True,则该字段允许为空白,默认值是False
    • 注意:
      • null是数据库范畴的概念,blank是表单验证范畴的
  • db_column
    • 字段的名称,如未指定,则使用属性的名称
  • db_index
    • 若值为True,则在表中会为此字段创建索引
  • defalut
    • 默认值
  • primary_key
    • 若为True,则该字段会成为模型的主键字段
  • unique
    • 若为True,则该字段的值必须唯一

关系

  • 分类
    • ForeignKey:一对多,将字段定义在多的端中
    • ManyToManyField: 多对多,将字段定义在两端中
    • OneToOneField:一对一,将字段定义在任意一端中。
  • 用一访问多:
    • 格式: 对象.模型类小写_set
    • 示例:grade.students_set
  • 用一访问一:
    • 格式:对象.模型类小写
    • 示例:grade.students
  • 访问id:
    • 格式:对象.属性_id
    • 示例:student.sgrade_id

创建模型类

  • models.py中创建即可

元选项

在模型类中定义一个Meta类,用于设置元信息(即信息)

  • 属性
    • db_table : 定义数据库表名,推荐使用小写字母。如果不写,数据表名默认为项目名小写_类名小写。
    • ordering : 对象的默认排序字段,获取对象的列表时使用。排序会增加数据库的开销。
class Students(models.Model):  
    sname = models.CharField(max_length=20)  
    sgender = models.BooleanField(default=True) # True表示男生,False表示女生  
    sage = models.IntegerField()    # 年龄  
    scontend = models.CharField(max_length=20) # 简介  
    isDelete = models.BooleanField(default=False) # 是否删除  
    # 关联外键  
    sgrade = models.ForeignKey("Grades", on_delete=models.CASCADE) # 关联Grade表的主键  

    lastTime = models.DateTimeField(auto_now=True) # 最后修改时间  
    createTime = models.DateTimeField(auto_now_add=True) # 创建时间  

    def __str__(self):  
        return self.sname  

    # 元数据  
    class Meta:  
        db_table = "students"  # 定义数据库表名  
        ordering = ["id"]  # 指明排序方式  
        # ordering = ["-id"] # 降序

模型成员

类属性

objects

  • 隐藏类属性objects : 是Manager类型的一个对象,作用是与数据库进行交互。
    • 当定义模型类时没有指定管理器,则Django为模型创建一个名为objects的管理器。

自定义管理器

  • 自定模型管理器后,自定后object就不存在了。
class Students(models.Model):  
    stuObj = models.Manager(); # 自定义管理器 , 自定义后objects就不存在了。

自定义管理器Manager类

  • 模型管理器时Django的模型进行预数据库交互的接口,一个模型可以有多个模型管理器。
  • 作用:
    • 向管理器类中添加额外的方法 ^a11ed7
    • 修改管理器返回其的原始集合(查询集)
      • 重写get_queryset()方法即可
  • test case

class StudentsManager(models.Manager):  
    def get_queryset(self):  
        return super(StudentsManager, self).get_queryset().filter(isDelete=False)  

class Students(models.Model):  
    stuObj = models.Manager() # 自定义管理器 , 自定义后objects就不存在了。  
    stuObj2 = StudentsManager() # 自定义管理器类

自定义属性

    sname = models.CharField(max_length=20)  

创建对象

  • 目的:
    • 向数据库中添加数据
  • 当创建对象时,Django不会对数据库进行读写操作。当调用save()方式时才与数据库进行交互,将对象保存到数据库表中。
  • 注意:

    • __init__方法已经在父类models.Model中使用,在定义模型中无法使用。
  • 方法
    • 在模型类中增加一个类方法
    class Students(models.Model):  
    stuObj = models.Manager() # 自定义管理器 , 自定义后objects就不存在了。  
    stuObj2 = StudentsManager() # 自定义管理器类  
    sname = models.CharField(max_length=20)  
    sgender = models.BooleanField(default=True) # True表示男生,False表示女生  
    sage = models.IntegerField(db_column="age")    # 年龄  
    scontend = models.CharField(max_length=20) # 简介  
    isDelete = models.BooleanField(default=False) # 是否删除  
    # 关联外键  
    sgrade = models.ForeignKey("Grades", on_delete=models.CASCADE) # 关联Grade表的主键  

    lastTime = models.DateTimeField(auto_now=True) # 最后修改时间  
    createTime = models.DateTimeField(auto_now_add=True) # 创建时间  

    def __str__(self):  
        return self.sname  

    # 元数据  
    class Meta:  
        db_table = "students"  # 定义数据库表名  
        ordering = ["id"]  # 指明排序方式  
        # ordering = ["-id"] # 降序  

    # 定义一个类方法创建对象  
    # cls 代表Student类  
    @classmethod  
    def createStudent(cls, name, age,gender,contented,grade,lastT,createT,isD=False):  
        stu = cls(sname = name,sage = age,sgender = gender,scontend = contented,sgrade = grade,lastTime=lastT,createTime = createT,isDelete = isD)  
        return  stu
    ```

    - 在自定义管理器类中添加一个方法 [[Django#^a11ed7]]

```python
class StudentsManager(models.Manager):  
    def get_queryset(self):  
        return super(StudentsManager, self).get_queryset().filter(isDelete=False)  

    def createStudent(self, name, age,gender,contented,grade,lastT,createT,isD=False):  
        stu = self.model() # 创建一个对象  
        print(type(stu))  
        stu.sname = name  
        stu.sage = age  
        stu.sgender = gender  
        stu.scontend = contented  
        stu.sgrade = grade  
        stu.lastTime = lastT  
        stu.createTime = createT  
        return stu

模型查询

概述

  • 查询集表示从数据库获取的对象集合
  • 查询集可以又多个过滤器
  • 过滤器就是一个函数,基于所给的参数限制查询集结果
  • 从sql角度来说,查询集合select语句等价,过滤器就像where条件

查询集

  • 在管理器上调用过滤器方法返回查询集合
class StudentsManager(models.Manager):  
    def get_queryset(self):  
        return super(StudentsManager, self).get_queryset().filter(isDelete=False)
        pass
  • 查询集经过过滤器筛选后返回新的查询集,所以可以写成链式标准
xxx.filter(xxx).filter(xxx).xxx
  • 惰性执行
    • 创建查询集会带来任何数据的访问,直到调用数据时,才会访问数据
  • 直接访问数据的情况
    • 迭代
    • 序列化
    • if合用
  • 返回查询集(多个数据)的方法称为过滤器
    • all() 返回查询集中的所有数据
    • filter() 返回符合条件的数据
      • filter(键=值)
      • filter(键=值,键=值) 两者同时满足
      • filter(键=值).filter(键=值) 两者同时满足
    • exclude() 过滤掉 符合条件的数据
    • order_by() 排序
    • values() 一条数据就是一个对象(字典),返回一个列表
  • 返回单个数据
    • get() 返回一个满足条件的对象
      • 注意
        • 如果没有找到符合条件对象,会引发模型类.DoesNotExist异常。
        • 如果找到多个对象, 会引发“模型类.MultipleObjectsReturned”异常
    • count() 返回当前查询集中的对象个数
    • first() 返回当前查询集中的第一个对象
    • last()返回当前查询集中的最后一个对象
    • exists() 判断查询集中是否有数据,如果有数据返回True,没有返回False
  • 限制查询集
    • 查询集是返回列表,可以使用下标的方法进行限制,等同于SQL中的LIMIT语句’
    • 注意下标不能是负数
# 分页显示学生  
def stupage(request,page):  
    # 0 - 5 , 5 - 10  
    page = int(page)  
    studentsList = Students.stuObj2.all()[(page-1)*5:page*5]  
    return render(request, 'myApp/students.html', {'students': studentsList})
  • 查询集的缓存
    • 概述
      • 每个查询集都包含一个缓存,来最小化的对数据库访问
      • 在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,Django会将查询出来的数据做一个缓存,并返回结果,后续查询直接直接使用查询集的缓存。
  • 字段查询
    • 概述:
      • 实现了SQL中的WHERE语句,作为方法filter(),exclude(),get()的参数
      • 语法:属性名称__比较运算符=值 (注意是两个_)
      • 外键是比较特殊的: 属性名_id
      • 转义:
        • SQL中的like中使用%是为了匹配占位的,想匹配数据中的%(WHER LIKE '\%')
        • filter(sname__contains='%') 不需要转义
    • 比较运算符
      • exact
        • 判断,大小写敏感
        • filter(isDelete=False)
      • contains
        • 是否包含,大小写敏感
      • startswith、endswith
        • 以value开头或结尾,大小写敏感
      • 以上四个在前面加上i,就表示不区分大小写。
        • iexact、icontains、istartswith、iendswith
      • isnull、isnotnull
        • 是否为空
      • in
        • 是否包含在范围内
      • gt,gte,lt,lte
        • 大于、大于等于、小于、小于等于
      • year、month、day、week_day、hour、minute、second
        • 日期
      • 跨关联查询
        • 处理join查询的
        • 模型类名__属性名__比较运算符
      • 查询快捷
        • pk : 代表主键
    • 聚合函数
      • 使用aggregate()函数返回聚合函数的值
      • Avg
      • Count
      • Max
      • Min
      • Sum
    • F对象
      • 可以使用模型的A属性与B属性进行比较(同一条数据的两个值进行比较)
        • Grades.objects.filter(ggirlnum__gt=F('gboynum'))
      • 支持F对象的算术运算
        • gradesList = Grades.objects.filter(ggirlnum__gt=F('gboynum')+30)
    • Q对象(解决的关系)
      • 概述
        • 过滤器的方法中的关键字参数,条件为And模式
      • 需求
        • 进行OR查询
      • 解决
        • 使用Q对象
      • 注意
        • 只有一个Q对象时,就是用于匹配的
        • 前面加~ 代表取非
from django.db.models import Max,F,Q,Min,Avg,Sum

def studentsearch(request):  
    # studentsList = Students.stuObj2.filter(sname__contains="孙%")  
    # studentsList = Students.stuObj2.filter(sname__contains="孙")   #包含孙  
    # studentsList = Students.stuObj2.filter(sname__startswith="张") #以张开头  
    # studentsList = Students.stuObj2.filter(pk__in=[2,4,6,8,10])    #in  
    # studentsList = Students.stuObj2.filter(sage__gte=30)           #大于等于  
    studentsList = Students.stuObj2.filter(lastTime__year=2017)      #年  
    grade = Grades.objects.filter(students__scontend__contains="薛延美") # 关联查询,描述中带有薛延美的学生是属于哪个班级?  
    print(grade)  

    maxAge = Students.stuObj2.aggregate(Max('sage'))  
    print(maxAge)  

    return render(request, 'myApp/students.html', {'students': studentsList})

def gradesF(request):  
    # get data  
    gradesList = Grades.objects.filter(ggirlnum__gt=F('gboynum'))  

    # send data to templates  
    # 将数据传递给模板,模板在渲染页面,模板将渲染好的页面返回给浏览器  
    return render(request, 'myApp/grades.html', {'grades': gradesList})

def studentsearch(request):  
    # studentsList = Students.stuObj2.filter(sname__contains="孙%")  
    # studentsList = Students.stuObj2.filter(sname__contains="孙")   #包含孙  
    # studentsList = Students.stuObj2.filter(sname__startswith="张") #以张开头  
    # studentsList = Students.stuObj2.filter(pk__in=[2,4,6,8,10])    #in  
    # studentsList = Students.stuObj2.filter(sage__gte=30)           #大于等于  
    # studentsList = Students.stuObj2.filter(lastTime__year=2017)      #年  
    # studentsList = Students.stuObj2.filter(students__scontend__)      #跨关联查询  
    studentsList = Students.stuObj2.filter(sname__contains="孙")  

    maxAge = Students.stuObj2.aggregate(Max('sage'))  
    print(maxAge)  

    return render(request, 'myApp/students.html', {'students': studentsList})

def studentQ(request):  
    studentsList = Students.stuObj2.filter(Q(pk__lte=3) | Q(sage__gte=30))  
    # studentsList = Students.stuObj2.filter(Q(pk__lte=3)) #   只有一个Q对象时,就是用于匹配的  
    # studentsList = Students.stuObj2.filter(~Q(pk__lte=3)) # 取非  
    return render(request, 'myApp/students.html', {'students': studentsList})

删除/更新

  • 查询到后,del对象在save即可删除
  • 查询到后,更新对象内容再save即可更新。


👇 Share | 分享 👇


要不赞赏一下?

微信
支付宝
PayPal
Bitcoin

版权声明 | Copyright

除非特别说明,本博客所有作品均采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。转载请注明转自-
https://www.emperinter.info/2022/05/29/django-models/


要不聊聊?

我相信你准备留下的内容是经过思考的!【勾选防爬虫,未勾选无法留言】

*

*



微信公众号

👉 NewsLetter ❤️ 邮箱订阅 👈

优惠码


阿里云国际版20美元
Vultr10美元
搬瓦工 | Bandwagon应该有折扣吧?
域名 | namesiloemperinter(1美元)