model模型
一 配置数据库
在settings.py中设置数据库
实例
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_demo',
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD':'root',
}
}
project的init.py如下:
import pymysql
pymysql.install_as_MySQLdb()
二 ORM—
随着项目越来越大,会产生大量SQL的方式 在代码中出现大量的SQL语句 就会出现如下问题:
- SQL重复利用率不高 越复杂SQL语句条件越多 代码会越长 出现很多相近的SQL语句
- 很多SQL语句在业务逻辑中拼接出来的 如果有数据库需要更改 就要去修改这些逻辑 这回很容易漏掉对某些语句的更改
- 写原生SQL语句时候 忽略WEB安全问题 给未来造成隐患
什么是ORM?
orm叫关系映射 通过ORM我们可以通过类的方式去操作数据库 而不用再去写原始SQL语句 通过把表映射成类 把行作为实例 把字段作为属性 ORM在执行对象操作数据库的时候 最终还是会转换成数据库原生SQL语句
使用ORM:
- 易用性 使用ORM做数据库开发 可以有效的减少重复SQL语句的概率 写出来的模型也更加直观有效清晰
- 性能消耗小 ORM转换成底层指令 确实会有一些开销 但从实际情况来看这种情况消耗很小 只要不对性能有严苛要求 综合考虑开发效率 代码的阅读性 带来的好处大于性能损耗 而且项目越大作用就越明显
- 设计灵活 可以轻松的写出复杂的SQL语句
- 可移植性 封装了底层数据句库的实现 支持多个关系型数据库的引擎 包括sqlite Mysql等数据库轻松切换数据库来去自如
三 模型的字段和可选性
- 字段类型
字段名称 | 字段说明 | 参数 |
---|---|---|
AutoField | 一个根据实际ID自动增长的interger 通常不指定 | |
CharField | varchar类型长文本 | max_length储存的最大长度 |
TextField | longtext类型长文本 | |
IntegerField | int类型字段 存储整形 | |
DecimalField | 存在浮点型更加精准(存储) | max_digits=None位数长度 decmal_places=None小数的位数 |
FloatField | 存储浮点类型 | |
BooleanField | 存储Bool值True/False | |
NullBooleanField | 存储null/True/False | |
DateField | date字段 | auto_now=False 如果对数据进行修改 则会自动保存修改的时间auto_now_add=False 会自动保存第一次保存的数据时间两个参数不能同事使用 |
TimeField | time字段 | 参数同上 |
DateTimeField | datetime字段 | 参数同上 |
- 字段选项
可选参数 | 参数说明 |
---|---|
null | 如果设置True则当前字段值可以为null |
blank | 如果设置为True则当前可以设置为什么都没有 |
db_column | 设置字段名称 不设置 字段则默认为属性名 |
db_index | 常规索引 |
unique | 唯一索引 |
primary_key | 主键索引 |
default | 默认值 |
四 定义模型
-
模型 数学 表之间的关系
一个模型类 对应数据库的一张表 一个类数学对应表中的一个字段 -
创建测试模型
models.py
from django.db import models
# Create your models here.
class Test(models.Model):
char = models.CharField(max_length=20, default='默认值', db_index=True)
text = models.TextField(null=True, blank=True)
inter = models.IntegerField(db_column='inte')
deci = models.DecimalField(max_digits=5, decimal_places=2)
float = models.FloatField()
bool = models.BooleanField()
null = models.NullBooleanField()
date = models.DecimalField(auto_created=True)
time = models.TimeField(auto_now=True)
datetime = models.DateTimeField(auto_now=True)
def __str__(self):
return self.char
注意
blank=True只能用在字符串的字段类型上,不能用在数值上
- 执行迁移 到数据库中
python3 manage.py makemigrations
python3 manage.py migrate
注意:
- 如果在执行创建迁移文件的时候 提示没有模型改变 那么就将新建的模型在别的视图文件中执行导入那么出现这种问题的原因(当前django莫有检测到你所写的类型)
- 默认模型的名字为 应用名_类名
4.元选项
在模型中定义一个Meta类:
from django.db import models
# Create your models here.
class Test(models.Model):
...
class Meta:
db_table = 'test' # 修改表名为test
ordering = ['id'] # 查询数据按照id升序
ordering = ['-id'] # 查询数据按照id降序
...
当对模型进行了修改 组需要再次执行文件迁移第3步操作
五 测试数据库
- 添加数据
def insert(req):
# 1.第一种添加数据
# t = Test()
# t.char = 'char'
# t.text = 'text'
# t.inter = 1
# t.float = 1.11
# t.deci = 1.234
# t.bool = True
# t.null = None
# t.save()
# 2.在实例化的时候传递参数
t = Test(char='char', text = 'text', inter = 1,float = 1.11,deci = 1.234, bool = True, null = True)
t.save()
return HttpResponse('添加')
- 查询数据
def select(req):
# 查询主键为1的数据 pk也就是primary_key的缩写
t = Test.objects.get(pk=1)
print(t)
# 根据属性获取出想要的数据
print(t.char)
print(t.deci)
print(t.float)
return HttpResponse('查询')
- 修改数据
# 修改
def update(req):
t = Test.objects.get(pk=1)
t.text = 'xiaole'
t.save()
return HttpResponse('修改')
- 删除数据
# 删除
def delete(req):
# 删除id= 2的数据
t = Test.objects.get(pk=2)
t.delete()
return HttpResponse('删除')
六 模型成员
类属性
-
object
是Manage类的一个对象 作用是与数据库交互
当定义模型的时候 没有指定模型管理器则Django会默认为当前模型类创建一个名为object的管理器 -
自定义模型管理器
class Test(models.Model):
...
# 当前的自定义模型管理器的名称
testobj = models.Manager()
注意
自定义模型管理器时候名称已发生改变名称testdb默认的object管理器已不存在了
视图函数中的使用
def delete(req):
# 删除id= 2的数据
t = Test.testdb.get(pk=2)
t.delete()
return HttpResponse('删除')
- 自定义模型管理器功能Manager类
概述
模型管理器是Django模型与数据库进行交互的借口可以有多个模型管理器
作用:- 向管理器中添加额外方法
- 修改管理器返回原始数据
- 重写get_query()_set()
实例
模板:
from django.shortcuts import render, HttpResponse
from App.models import User
import random
# 添加数据
def add(req):
u = User()
firstname = ['赵','钱', '孙', '李', '周', '吴', '郑', '王']
lastname = ['按', '上', '类', '会', '才', '为', '给', '恶']
num = random.randrange(1, 3)
newname = firstname[random.randrange(len(firstname))]
for i in range(num):
newname += lastname[random.randrange(len(lastname))]
u.username = newname
u.sex = [True, False][random.randrange(2)]
u.age = random.randint(1, 100)
u.info = '我是{}的简介'.format(newname)
u.save()
return HttpResponse('添加数据')
medles.py:
class User(models.Model):
username = models.CharField(db_index=True, max_length=20, default='xiaole')
sex = models.BooleanField(default=True)
age = models.IntegerField(default=18)
info = models.CharField(default='瞎联系', max_length=20)
createtime = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.username
class Meta:
db_table = 'user'
类方法添加与查询:
models.py
class User(models.Model):
username = models.CharField(db_index=True, max_length=20, default='xiaole')
sex = models.BooleanField(default=True)
age = models.IntegerField(default=18)
info = models.CharField(default='瞎联系', max_length=20)
createtime = models.DateTimeField(auto_now_add=True)
@classmethod
def addUser(cls, username='xiaole', sex=True, age=18, info='说明'):
obj = cls(username=username, sex=sex, age=age, info=info)
return obj
def __str__(self):
return self.username
class Meta:
db_table = 'user'
模板
def showData(req):
u = User.objects.all()
return render(req, 'show_data.html', {'data':u})
# 自定义方法
def myAdd(req):
u = User.addUser('xiaole', False, 18, 'xiaole的简介')
u.save()
return HttpResponse('自定义类方法添加')
七 模型查询
概述:
1. 查询集表示从数据库中拿到的对象集合
2. 查询集可以有多个过滤
3. 过滤器是一个函数 根据所给的参数限制返回的查询集
4. 从sql角度来说 查询集合和select语句等价 过滤器就是sql语句的where条件
1.操作原生SQL语句
def showData(req):
# u = User.objects.all()
# 原生查询
# 注意原生查询在Linux下区分大小写
u = User.objects.raw('select * from user')
u = User.objects.raw('select * from user')[0:5]
u = User.objects.raw('select * from user')[0]
# return HttpResponse(u)
u = User.objects.raw('select * from user limit 5')
return render(req, 'show_data.html', {'data':u})
2. all() 方法查询集中所有数据
类名.objects.all()
切片操作 节约内存
实例
def showData(req):
u = User.objects.all()
u = User.objects.all()[0:4]
return render(req, 'show_data.html', {'data':u})
实现分页案例
def showData(req):
try:
page = int(req.GET.get('page', 1))
except:
page = 1
u = User.objects.all()[(page-1)*3:page*3]
return render(req, 'show_data.html', {'data':u})
ur:lhttp://127.0.0.1:8000/show_data/?page=1
3.filter()将符合条件返回
类名.objects.filter(属性名=值…)
如果参数为多个 那么为and操作
实例
# 查询性别为True
u = User.objects.filter(sex=True)
# 查询性别为True且姓名包含李
u = User.objects.filter(sex=True, username__contains='李')
# 查询性别为True且姓名包含李
u = User.objects.filter(sex=True).filter(username__contains='李')
exclude()过滤符合条件的数据
类名.objects.exlude(属性名=值)
实例
u = User.objects.exclude(sex=True)
# 查询性别不为True且姓名不包含李
u = User.objects.exclude(sex=True, username__contains='李')
# 查询性别不为True且姓名不包含李
u = User.objects.exclude(sex=True).filter(username__contains='李')
return render(req, 'show_data.html', {'data':u})
5.order_by()
- 升序
order_by(‘id’) - 降序
order_by(’-id’)
u = User.objects.order_by('id')
可以根据上面filter()结合使用
6.reverse()反转
对order_by的反转
u = User.objects.order_by('id').reverse()
7.values()返回一个列表 每条数据是一个字典
类名.objects.values()
u = User.objects.values()
# 根据字段返回结果
u = User.objects.values('id', 'username', 'age')
8.value_list()得到一个元祖格式的数据 只有值
类名.objects.values_list()
u = User.objects.values_list()
返回一条数据(一个对象)
- get()返回一个对象
u = User.objects.get(pk=1)
注意:
- 只能匹配一条数据 如果多条会报错
- 如果匹配失败会抛出异常
- 只能匹配一条数据
count() 返回统计条数
u = User.objects.count()
first()取出第一条数据
u = User.objects.first()
last()取出第一条数据
u = User.objects.last()
exists()判断数据是否存在返回bool值
u = User.objects.exists()
比较运算符
(1).完全匹配运算符
- _exact对大小写敏感
- _iexact对大小写不敏感
u = User.objects.filter(username_exac='xiaole')
(2)._contains() 包含大小写敏感
u = User.objects.filter(username_contains='xiaole')
u = User.objects.filter(username_contains='XIAOLE')
(3)._startswith _endswith 以…开头 以…结尾
不区分大小写
u = User.objects.filter(username_startswith='x')
(4).null 查询
u = User.objects.filter(username=None)
u = User.objects.filter(username_isnull=True)
u = User.objects.filter(username_isnull=False)
(5).in/not in 是否在…里
_in/not in[值1, 值2]
(6).range值的范围
_range[start, end]
(7).比较运算付
- __gt 大于
- __gte 大于等于
- __lt 小于
- __lte 小于等于
(8).extra 实现别名操作
# extra其别名将userneme区别名为xx
u = User.objects.all().extra(select={'xx':'username'})
聚合函数
导入:from django.db.models import Avg, Max, Min, Sum, Count
avg =User.objects.aggregate(Avg('age'))
avg =User.objects.aggregate(Count('age'))
avg =User.objects.aggregate(Max('age'))
avg =User.objects.aggregate(Min('age'))
avg =User.objects.aggregate(Sum('age'))
Q对象与F对象
导入from django.db.models import Q, F
Q对象
作为or查询来使用
u = User.objects.filter(Q(age_exact=18)| Q(sex=True))
F对象
使模型A的属性与B的属性做比较
# age比id大的数据
u = User.objects.filter(age__gte=F('id'))
八 数据修改
- save()
- update()
区别
1. save() 对单个对象的修改
2. update() 适用于多个对象的修改
九 模型对应关系
有以下三种关系:
- 1:1 一对一模型关系
- 1:N一对多模型关系
- M:N多对多模型关系
其中一对一和一对多有共同使用的属性
on_delete:
- models.CASEDE默认值 当主表的数据删除 则从表数据默认跟随删除
- models.PROTECT 保护模式 主表数据一旦被删除 从表数据为保护模式不删除
- models.SET_NULL 致空模式 当主表数据删除 从表数据外键字段的值 设置为null 但是前提是字段要设置为null=True
注意:
建议把模型关系字段存放在从表中
(1).一对一
使用OneToOneField创建一对一模型关系
from django.shortcuts import render, HttpResponse
from App.models import User, Idcard
import random
# 测试模型关系vivews
# 模型一点意义的添加
def addUser(req):
u = User()
firstname = ['赵','钱', '孙', '李', '周', '吴', '郑', '王']
lastname = ['按', '上', '类', '会', '才', '为', '给', '恶']
num = random.randrange(1, 3)
newname = firstname[random.randrange(len(firstname))]
for i in range(num):
newname += lastname[random.randrange(len(lastname))]
u.username = newname
u.sex = [True, False][random.randrange(2)]
u.age = random.randint(1, 100)
u.info = '我是{}的简介'.format(newname)
u.save()
return HttpResponse('添加数据')
# 添加卡信息
def addIdCard(req):
u = User.objects.get(pk=25)
idCard = Idcard()
idCard.num = random.randrange(10000,100000)
idCard.name = u.username
idCard.user = u # 存储关联外部user_id的值
idCard.save()
return HttpResponse('卡信息添加成功!')
一对一查询
# 一对一查询
def selectIdCard(req):
# idcard = Idcard.objects.get(pk=1)
# print(idcard.user)
# print(idcard.user.info)
u = User.objects.get(pk=25)
print(u.idcard)
return HttpResponse('一对一查询')
一对一删除
# 一对一删除
def deleteIdcard(req):
idcard = Idcard.objects.get(pk=1)
idcard.delete()
return HttpResponse('一对一删除')
(2).模型一对多的关系
使用foreignKey创建模型一对多对应关系
# 创建班级
class Grade(models.Model):
name = models.CharField(max_length=20)
num = models.IntegerField(default=40)
girlnum = models.IntegerField(default=20)
boynum = models.IntegerField(default=20)
def __str__(self):
return self.name
class Meta:
db_table = 'grade'
# 创建学生表
class Student(models.Model):
name = models.CharField(max_length=10)
sex = models.BooleanField(default=True)
age = models.IntegerField(default=20)
grade = models.ForeignKey(Grade, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
db_table = 'student'
#添加年级
def addGrade(req):
g = Grade()
g.name = '班级'+str(random.randint(1,10))
g.save()
#添加学生
def addStu(req):
stu = Student()
stu.name = ...
stu.grade = Grade.object.first()
stu.add()
...
def selectmsg(req):
# 查询主表 班级下有哪些学生
g = Grad.object.first()
# 查询学生是那个班的
s = Student.object.first()
return ...
根据以上一对一与一对多有共同使用的属性
on_delete:
- models.CASEDE默认值 当主表的数据删除 则从表数据默认跟随删除
- models.PROTECT 保护模式 主表数据一旦被删除 从表数据为保护模式不删除
- models.SET_NULL 致空模式 当主表数据删除 从表数据外键字段的值 设置为null 但是前提是字段要设置为null=True
设置主表的属性:
user = models.OneToOneField(User, on_delete=models.CASCADE) # 设置一对一的模型关系
user = models.OneToOneField(User, on_delete=models.PROTECT) # 受保护模式 主表删除数据从表不变
user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True) # 受保护模式 主表删除数据 从表外键设置为空