04 Django模型基础

1. models字段类型

概述

django根据属性的类型确定以下信息

  • 当前选择的数据库支持字段的类型
  • 渲染管理表单时使用的默认html控件
  • 在管理站点最低限度的验证

django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后则django不会再生成默认的主键列
属性命名限制

  • 遵循标识符规则

  • 由于django的查询方式,不允许使用连续的下划线定义属性时,

    需要字段类型,字段类型被定义在diango.db.models.fields目录下,为了方便使用被导入到django.db.models中
    使用方式

  • 导入from django.db import models

  • 通过models.Field创建字段类型的对象,赋值给属性
    逻辑删除和物理删除

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

is_delete = models.BooleanField(default=False)
常用字段类型

  • AutoField: 一个根据实际ID自动增长的IntegerField,通常不指定,如果不指定,主键字段id将自动添加到模型中

  • CharField(max_length=字符长度)

    • 字符串,默认的表单样式是 Input
  • TextField

    大文本字段,一般超过4000使用,默认的表单控件是Textarea

  • IntegerField

    • 整数
  • DecimalField(max_digits=None,decimal_places=None)

    • 使用python的Decimal实例表示的十进制浮点数
    • 参数说明
      • DecimalField.max_digits -> 位数总数
      • DecimalField.decimal_places -> 小数点后的数字位数
  • FloatField: 用Python的float实例来表示的浮点数

  • BooleanField

    • True/False 字段,此字段的默认表单控制是CheckboxInput
  • DateField([auto_now=False,auto_now_add=False])

    • 使用Python的datetime.date实例表示的日期参数说明
    • 参数说明
      • DateField.auto_now
        每次保存对象时,自动设置该字段为当前时间,用于**"最后一次修改"**的时间戳,它总是使用当前日期,默认为false
      • DateField.auto_now_add
        当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用创建时的日期,默认为false
      • 注意:auto_now_add,auto_now,and_default 这些设置是相互排斥的他们之间的任何组合将会发生错误的结果
  • TimeField: 使用Python的datetime.time实例表示的时间,参数同DateField

  • DateTimeField: 使用Python的datetime.datetime实例表示的日期和时间,参数同DateField

  • FileField

    • 一个上传文件的字段
  • ImageField:

    • 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
    • 需要安装Pillow: "pip install Pillow"

2. 常用字段参数

python 复制代码
# 常用字段选项(通过字段选项,可以实现对字段的约束)
	1. null=True
		数据库中字段是否可以为空
	2. blank=True
		django的 Admin 中添加数据时是否可允许空值

	一般null=True & blank=True 搭配着用,出现null=True就用上blank=True
    
	3. primary_key = True
    	主键,对AutoField设置主键后,就会代替原来的自增id列
        
    4. auto_now和auto_now_add
        auto_now 自动创建 --- 无论添加或修改,都是当前操作的时间
        auto_now_add 自动创建 --- 永远是创建时的时间
        
    5. choices (后台admin下拉菜单)
        USER_TYPE_LIST =(
        (1,'超级用户'),
        (2,'普通用户'), 
        )
		user_type = models.IntegerField(choices=USER_TYPE_LIST,default=1,,verbose_name='用户类型')
        
    6. max_length 最大长度
	7. default 	  默认值
	8. verbose_name		Admin(后台显示的名称)中字段的显示名称
	9. name|db_column	数据库中的字段名称
	10. unique=True		不允许重复
	11. db_index = True	数据库索引,例如:如果你想通过name查询的更快的话,给他设置为索引即可
    12.	editable=True 	在Admin里是否可编辑,不可编辑则不显示
	13. 设置表名
	class Meta:
		db_table ='person'

在创建模型迁移之时,经常会遇到以下问题,这是以为原先数据库中已经有数据,这时创建新的数据字段,原先的记录不知道填充什么内容进新增字段(假设不是所有新增字段都有默认值)

模型在admin后台默认的html控件 --> 渲染管理表单时使用的默认html控件

3.迁移怎么回滚

完成迁移之后,会在应用文件夹App/migrations文件夹下创建迁移文件,并且在数据库表django_migrations中创建对应记录

想要回滚,可以删除对应的迁移python文件以及对应数据库记录


4. models基本操作

一般的数据库操作流程:

  1. 创建数据库,设计表结构和字段
  2. 连接Mysql数据库,并编写数据访问层代码
  3. 业务逻辑层去调用数据访问层执行数据库操作

Django通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite,Django自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Django帮我们自动完成。

只要会写Model就可以了。django使用对象关系映射(Object Relational Mapping,简称ORM)框架去操控数据库。ORM(Object Relational Mapping)对象关系映射,是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

在Django模型中可以使用内部类Meta为模型提供选项,具体请见文档

增删改查

ORM

  • 模型 <=> 表
  • 类结构 -> 表结构
  • 对象 -> 表的一条数据
  • 类属性 -> 表的字段

模型基本操作

  1. 增: (假设模型是Author)

    1. 创建对象实例,然后调用save方法
    python 复制代码
    obj = Author()
    obj.first_name = "zhang"
    obj.last_name = 'san'
    obj.save()
    1. 创建对象并初始化,在调用save方法
    python 复制代码
    obj = Author(first_name = "zhang",last_name = 'san')
    obj.save()
    1. 使用create方法
    python 复制代码
    Author.objects.create(first_name = "zhang",last_name = 'san')
    1. 使用get_or_create方法,可以防止重复
    python 复制代码
    Author.objects.get_or_create(first_name = "zhang",last_name = 'san')

注意: 添加失败是因为PersonModel模型中name属性设置的是unique

python 复制代码
# 增加数据
def add_person(request):
    # # 方式1
    # try:
    #     p = PersonModel(name='张三', age=20)
    #     p.save()
    # except Exception as e:
    #     print(e)
    #     return HttpResponse('添加失败')

    # return HttpResponse('添加成功')

    # 方式2
    # PersonModel.objects.create(name='李四', age=25)
    # return HttpResponse('添加成功')

    # 方式3
    ret = PersonModel.objects.get_or_create(name='李四', age=25)
    print("ret",ret)
    # ret:(<PersonModel:PersonModelobject(2)>,True)
    # 如果是第一次创建: 则是True,如果已经存在则是False
    return HttpResponse('添加成功')
  1. 删:

    1. 获取单个对象并调用Queryset的delete()方法
    python 复制代码
    p = PersonModel.objects.first() # 获取第一个数据
    p.delete()
    p = PersonModel.objects.get(name="李四")   # 根据对应的id获取数据
    p.delete()

    注意: objects不能直接调用delete()方法
    2. 使用模型过滤filter(),再对过滤结果进行删除

    python 复制代码
    # 使用过滤器
    PersonModel.objects.filter(age__gt = 15).delete()   # 删除年龄大于15的数据        
  2. :

    1. 直接使用对象.属性修改
    python 复制代码
    # 获取数据
    p = PersonModel.objects.first()
    p.age = 25
    p.save()
    
    # 修改多条数据
    p_list = PersonModel.objects.all()
    
    for p in p_list:
    	p.age = 25
       	p.save()
    1. 修改多条数据
    python 复制代码
    PersonModel.objects.all().update(age=25)  # 修改所有数据

    save()更新时,会对所有字段进行更新操作,如果想要只更新某个字段,减少数据库操作,可以这么做:

    python 复制代码
    obj.first_name = "zhang"
    obj.save(update_fields = ['first_name'])
  3. 查:

对查询集可使用的函数

  • get():获取单条数据 Author.objects.get(id=123)

    • 如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常
    • 如果找到多个,会引发模型类.MultipleObjectsReturned异常
  • first():返回査询集(Queryset)中的第一个对象

  • last():返回查询集中的最后一个对象

  • count():返回当前查询集中的对象个数

  • exists():判断查询集中是否有数据,如果有数据返回True没有反之

  • all()获取全部数据: Author.objects.all()

  • values():获取指定列的值,可以传多个参数! 返回包含字典的列表(保存了字段名和对应的值) --->

    Author.objects.all().values('password')

  • values_list():获取指定列的值,可以传多个参数! 返回包含元组列表(只保存值) --->

    Author.objects.all().values_list('password')

  • filter()

查询集可以被链式调用,Author.objects.filter(name="seven").filter(age=18)

进阶操作
python 复制代码
# 获取个数
Author.objects.filter(name="seven").count()

# 获取id大于1的值
Author.objects.filter(id__gt=1)	# SELET * FROM Author WHERE id > 1
# 获取id大于或等于1的值
Author.objects.filter(id__gte=1)	# SELET * FROM Author WHERE id >= 1
# 获取id小于10的值
Author.objects.filter(id__lt=10)	# SELET * FROM Author WHERE id < 10
# 获取id小于或等于10的值
Author.objects.filter(id__lte=10)	# SELET * FROM Author WHERE id >= 1

# 获取id大于1且小于10的值
Author.objects.filter(id__lt=10,id__gt=1)	# SELET * FROM Author WHERE id > 1 AND id < 10
# 获取id在11,22,33的数据
Author.objects.filter(id__in=[11,22,33])	# SELET * FROM Author WHERE id IN (11,22,33)

# 获取id`不在`11,22,33的数据
Author.objects.exclude(id__in=[11,22,33])	# SELET * FROM Author WHERE id NOT IN (11,22,33)

# 获取name包含"ven"的数据 (和数据库中like语法相似)
Author.objects.filter(name__contains="ven")	# SELET * FROM Author WHERE name LIKE '%ven%'

# icontains()大小写不敏感
Author.objects.filter(name__icontains="ven")

Author.objects.filter(name_regex="^ven")	# 正则匹配
Author.objects.filter(name_iregex="^ven")	# 正则匹配,忽略大小写
Author.objects.filter(age_range=[10,20])   	# 范围bettwen and

# startswith,istartswith,endswith,iendswith:
# 以什么开始,以什么结束,和上面一样带i的是大小写不敏感的, 其实不带i的也忽略大小写

Author.objects.filter(name='seven').order_by('id','age')	# asc升序, 多个属性->id相同时,按照age来排序
Author.objects.filter(name='seven').order_by('-id')	# desc降序

Author.objects.all()[18:20] # 切片,取所有数据的18条到20条,分页的时候用的到
# 下标从0开始,不能为负数,可以实现分页

# 手动分页
page 页码 
per_page 每页数量 = 5
第1页(page=1): 0-4 =>[0:5]
第2页(page=2): 5-9 =>[5:10]
第3页(page=3): 10-14 =>[10:15]
第4页(page=4): 15-19 =>[15:20]

每一页数据范围:[(page-1) * per_page : page * per_page]

# 聚合
使用aggregate()函数返回聚合函数的值
- Avg:平均值
- Count:数量
- Max:最大
- Min:最小
- Sum:求和
from django.db.models import Count,Min,Max,Sum
Author.objects.aggregate(Max('age'))

5. views.py

python 复制代码
from django.http import HttpResponse
from django.shortcuts import render
from django.db.models import Avg, Max, Min, Sum
# Create your views here.

from App.models import *


# 增加数据
def add_person(request):
    # # 方式1
    # try:
    #     p = PersonModel(name='张三', age=20)
    #     p.save()
    # except Exception as e:
    #     print(e)
    #     return HttpResponse('添加失败')

    for i in range(10):
        p = PersonModel(name='张三'+str(i), age=20+i)
        p.save()

    # return HttpResponse('添加成功')

    # 方式2
    # PersonModel.objects.create(name='李四', age=25)
    # return HttpResponse('添加成功')

    # 方式3
    # ret = PersonModel.objects.get_or_create(name='李四', age=26)
    # print("ret",ret)
    # ret:(<PersonModel:PersonModelobject(5)>,True)
    # 如果是第一次创建: 则是True,如果已经存在则是False
    return HttpResponse('添加成功')


# 删除数据
def del_person(request):
    try:
        # p = PersonModel.objects.first() # 获取第一个数据
        # p = PersonModel.objects.get(name="李四")   # 根据对应的id获取数据
        # p.delete()
        # 使用过滤器
        PersonModel.objects.filter(age__gt = 15).delete()   # 删除年龄大于15的数据
        
    except Exception as e:
        print(e)
        return HttpResponse('删除失败')
    
    return HttpResponse('删除成功')

# 修改数据
def update_person(request):
    try:
        # 获取数据
        # p = PersonModel.objects.first()
        # p.age = 25
        # p.save()

        # 修改多条数据
        p_list = PersonModel.objects.all()
        # PersonModel.objects.all().update(age=25)  # 修改所有数据
        for p in p_list:
            p.age = 25
            p.save()
    except Exception as e:
        print(e)
        return HttpResponse('修改失败')
    
    return HttpResponse('修改成功')

        
def get_person(response):
    # get() 方法获取单个数据
    # p = PersonModel.objects.get(id=1)

    # p = PersonModel.objects.get(pk=18)    # primary key等于18
    # p = PersonModel.objects.get(age=100)  # 找不到对应的数据时会报错,找到多条数据时也会报错   
    # print(p,type(p))    # <PersonModel: PersonModelobject(1)> <class 'App.models.PersonModel'>
    # print(p.name,p.age)

    # all() 方法返回所有数据
    p_list = PersonModel.objects.all()
    print(p_list,type(p_list))  #  <PersonModel: PersonModel object (25)>]> <class 'django.db.models.query.QuerySet'> 查询集,可以遍历

    # first() 方法获取第一个数据
    # p = PersonModel.objects.first()

    # last() 方法获取最后一个数据   
    # p = PersonModel.objects.last()

    # exists() 方法判断数据是否存在
    # if PersonModel.objects.filter(name='张三').exists():
    #     print('存在')
    # else:
    #     print('不存在')

    # values() 方法返回指定字段的数据
    # p_list = PersonModel.objects.values('name','age')   #返回包含字典的列表
    p_list = PersonModel.objects.values_list('name','age')   # 返回包含元组列表
    print(p_list,type(p_list))

    # filter() 方法过滤数据,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.filter(age__gt=15)   # 年龄大于15的数据
    # p_list = PersonModel.objects.filter(name__contains='三')   # 名字包含'三'的数据
    # p_list = PersonModel.objects.filter(name__startswith='张')   # 名字以'张'开头的数据

    # exclude() 方法排除数据,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.exclude(age__gt=15)   # 年龄不大于15的数据

    # order_by() 方法排序数据,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.order_by('age')   # 按年龄排序
    # p_list = PersonModel.objects.order_by('-age')   # 按年龄倒序排序

    # contains() 方法查找字符串是否在指定字段中,返回一个```查询集````,参数为空时返回所有数据
    p_list = PersonModel.objects.filter(name__contains='三')   # 名字包含'三'的数据
    print(p_list,type(p_list))

    # regex() 方法查找正则表达式是否匹配指定字段,返回一个```查询集````,参数为空时返回所有数据
    # p_list = PersonModel.objects.filter(name__regex=r'^张')   # 名字以'张'开头的数据

    # 聚合函数
    # count() 方法计算数据条数
    # count = PersonModel.objects.count()
    # print(count)

    # max() 方法获取最大值
    # max_age = PersonModel.objects.all().aggregate(Max('age'))
    # print(max_age)

    # min() 方法获取最小值
    # min_age = PersonModel.objects.all().aggregate(Min('age'))
    # print(min_age)

    # sum() 方法求和
    # total_age = PersonModel.objects.all().aggregate(Sum('age'))
    # print(total_age)

    # avg() 方法求平均值
    result = PersonModel.objects.all().aggregate(Avg('age'))
    print(result)

    return HttpResponse('获取成功')


# 分页数据
def paginate(request,page=1):
    # 页码: page
    # 每页显示条数: per_page
    per_page = 10
    # 数据范围的计算公式 -> (页码-1)*每页显示条数 ~ 页码*每页显示条数

    all = PersonModel.objects.all()
    start = (page-1) * per_page
    end = page * per_page
    p_list = all[start:end]
    return render(request,"page_list.html",{'p_list':p_list})


# 自动分页器
def auto_paginate(request):
    # 自动分页器
    from django.core.paginator import Paginator
    # 实例化分页器
    paginator = Paginator(PersonModel.objects.all(), 10)
    page = 1
    persons = paginator.page(page) # 获取第page页的数据
    paginator.page_range   # 页码范围,可以遍历
相关推荐
DashVector4 分钟前
如何通过HTTP API新建Collection
数据库·人工智能·http·阿里云·向量检索
Tiandaren19 分钟前
从Python到C++的转变之路——如何高效复现C++开源项目 || Windows || Visual Studio || 持续更新
开发语言·c++·图像处理·人工智能·python·深度学习·开源
古希腊掌管学习的神28 分钟前
[机器学习]XGBoost(4)——系统设计(含代码实战)
人工智能·python·机器学习
码农老起1 小时前
数据库设计的基础与进阶:1NF、2NF、3NF及BCNF解析
数据库·oracle
看海的四叔1 小时前
【Python】主成分分析PCA - 算法、问题与Python实现
人工智能·python·算法·机器学习·数据分析
小小小妮子~1 小时前
MySQL专题:日志及MVCC
数据库·mysql
<e^πi+1=0>1 小时前
使用k6进行Redis基准测试
数据库·redis·缓存
YONG823_API1 小时前
1688跨境代购代采业务:利用API实现自动化信息化
大数据·数据库·人工智能·爬虫·缓存·数据挖掘
PingCAP1 小时前
B 站数据库负责人赵月顺:助力海内外业务增长,百套 TiDB 的选型与运维实战
数据库·分布式·tidb