模型01
一、MTV概述
1. Model - 模型 :模型是数据的唯一可靠的来源,实际上是要与数据库交互。
2. Template - 模板: 使用HTML来给用户展示界面
3. Views - 视图(函数): 负责接收请求处理业务逻辑,视图也是数据库和模板的中间人。
二、ORM机制
ORM:
Object Relational Mapping - 对象关系映射(面向对象和关系性数据库之间的一种映射关系)
核心:
采用面向对象的方式与数据库进行交互
对比:
未使用ORM之前:
import MySQLdb
conn = MySQLdb.connect(xxx)
...
cursor.execute(insert / select ) #使用原生的SQL语句
...
conn.close()
使用ORM之后:
类和对象
class User(models.Model):
username = xxx
password = xxx
在ORM中,这样的一个类,对应的是数据库中的一张表
存储数据: user = User(username,password) user.save() # 将数据存储到数据库表中
优势(了解):
1. 使用面向对象的方式更符合程序员的思维方式
2. 使用ORM的方式操作数据库,更加简单和方便
3. 使用ORM程序员无需关心程序底层使用的是MySQL、Oracle、SQLite等,更换数据库时,ORM会自动进行转换
三、Model层的开发过程
基本开发流程
1. 安装数据库驱动
pip install mysqlclient
2. 配置数据库settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 修改为mysql
'NAME': 'modeldb', # 库名
'HOST': '127.0.0.1', # 主机名 ip
'PORT': 3306, # 端口号
'USER': 'root', # 用户名
'PASSWORD':'123456' # 密码
}
}
# 如果出现版本不兼容 则添加以下配置
from django.db.backends.mysql.base import DatabaseWrapper
DatabaseWrapper.data_types['DateTimeField'] = "DateTime"
3. 创建一个app,并挂载app
python manage.py startpp modelapp
在settings.py文件的 INSTALLED_APPS = [xxx,'modelapp']
4. 打开models.py 定义model类
# 这里定义的model将来会对应库中的一张表
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=20)
5. 执行迁移操作
# 在terminal中执行以下指令:
python manage.py makemigrations # 生成一个记录文件 此时模型并没有生成到数据库
python manage.py migrate # 会根据model类生成一张表 数据库已经有了对应的表
测试model
# 总结:
ORM对象关系映射:
1. 一个model类对应数据库中的一张表
2. 类中的属性对应表中的字段
3. 一个model类的对象对应的是表中的一行数据
要操作一行数据,就是操作一个model对象,要操作一个字段就是操作对象的属性,要操作表就是操作
四、模型字段
1、字段类型
字段类型 | 描述 |
---|---|
AutoField | 一般不直接使用,默认为主键的类型,不需要自己定义 |
SmallIntegerField | 数据库中的:smallint 2字节 |
IntegerField | 数据库中的:int 4字节 -2147483648~2147483647 |
BigIntegerField | 数据库中的:bigint 8字节 |
FloatField | 数据库中的:double |
Decimal(max_digits=5,decimal_places=2) | 数据库中的:decimal(5,2) |
CharField(max_length=20) | 数据库中的:varchar(20) |
TextField | 数据库中的:longText 长文本 |
BooleanField (值:True / False) | 数据库中的:tinyint (1和0) |
NullBooleanField(值:True / False / None) | 数据库中的:tinyint (1 / 0 / null) |
DateField | 数据库中的:date |
TimeField | 数据库中的:time |
DateTimeField | 数据库中的:datetime 可选参数:auto_now=True 表示更新时间或auto_now_add=True第一次添加时间 |
ForeignKey | 外键字段 一对多 |
OneToOneField | 一对一 |
ManyToManyField | 多对多 |
2、字段参数
1. null 默认为False 不能为空
name = models.CharField(max_length=20,null=False) 字段默认不能为空
name = models.CharField(max_length=20,null=True) 字段可以为空
2. default 定义默认值
name = models.CharField(max_length=20,default='jingjing')
# 这里定义的默认值并不会作用到数据库表中,仅仅表示将来构造对象时可以不添加该参数
# e = Employee(age=18,gender=True) e.save()
3. primary_key 定义主键 (不常用)
id = models.AutoField(primary_key=True) # 一般不自己定义
4. unique 唯一
name = models.CharField(max_length=20,unique=True) # 名字是唯一的 不能重复
5. db_column 定义字段的别名 (不常用)
# 定义该字段在数据库中的列名 如果不指定则使用属性 指定则db_column的值为准
gender = models.BooleanField(db_column='xb') # 一般不建议修改列名
6. db_index 定义索引
age = models.SmallIntegerFeild(db_index=True) # age列就有了索引
# select * from employee where age=18;
3、Meta元数据
# 元数据类:可以指定生成的表名、排序方式、联合约束等
1. db_table = 'xx' 定义表名
2. ordering = ['列名'] 或 ['-列名'] 或 ['列名1','列名2'] 定义排序规则
3. unique_together = ('列名1','列名2') 或 ( ('列名1','列名2') , ('列名3','列名4') )
class User(models.Model):
xxx
class Meta:
db_table = '表名'
五、增删改操作
这一节,需要使用model类(对象),来对数据库进行增删改操作以下代码可以如下执行: 方式一:将代码写在视图函数中,然后在浏览器中输入URL访问 方式二:打开pycharm左下角的Python Console,然后导入model类 from modelapp.models import User 方式三: 在tests.py文件或自己新建一个.py文件,加入以下代码 import django,os # 导入django和os包 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_lession_2005.settings") # 将manage.py文件的第6行复制过来 django.setup() from modelapp.models import User # 导入model类 # 这里写测试代码 # 使用右键run 单文件
1、增加数据(创建对象)
# 方式一: 先创建对象再调用save方法user = User(name='Tom', age=18, salary=23451, birthday='2000-1-1')user.save()# 方式二: 直接使用类名.objects.create()即可User.objects.create(name='Jack',age=20,salary=12341,birthday='2002-2-1')
2、删除数据
# 1. 先获取数据 user = User.objects.get(id=1) print(user)# 2. 然后调用delete方法 user.delete()# 删除所有行users = User.objects.all()users.delete()
3、修改数据
# 1. 获取数据user = User.objects.get(id=4)# 2. 修改数据 - 实际就是操作对象的属性user.age = 50# 3. 调用save保存到数据库 -- 切记一定要保存user.save()
六、查询操作
1、QuerySet类
1. 每一个model类,都有一个objects属性(类名.objects),该属性的类型为manager类型 t = User.objects print(type(t)) # 类型为Manager --<class 'django.db.models.manager.Manager'> 2. 对对象的检索(查询),都通过Manager来构造一个QuerySet对象来实现的 user = User.objects.get(id=1) 上述代码中,看到的是Manager调用它的get方法实现了查询,但实际情况是Manager构造了一个QuerySet对象来实现的查询 3. Manager对象和QuerySet对象的关系: Manager是一个管理者,它不是真正的执行者 -- 不是真正干活的人 QuerySet是实际执行查询操作的,它才是真正干活的人 4. User.objects.all() 是Manager调用了all()方法,但它的内部并没有直接执行查询操作,而是让QuerySet调用了all()方法执行的查询操作 5. all()方法的返回值 QuerySet对象 -- 查询集 它本身是可以执行查询操作也可以存放查询结果
2、查询方法
如下所有的查询方法都是QuerySet实现的,只不过每个Model类在做查询操作时,都是先交给Manager,然后Manager接收到查询请求后,调用QuerySet对应的方法最终实现查询。所以QuerySet是查询动作的核心支撑.Manager的任务是管理QuerySet,在有需要的时候去调用QuerySet.
2.1 基本查询方法
1. all()方法 用法: User.objects.all() 作用: 查询全部数据 返回值:QuerySet对象 - 类似于一个列表,每一个元素是Model对象 <QuerySet [<User: User object (1)>, <User: User object (2)> ...] 2. get()方法 用法:User.objects.get(属性名=值) 作用:只能查询一条数据(不能多不能少) 返回值:Model对象 eg: User.objects.get(id=1) User.objects.get(pk=1) User.objects.get(age=18) # 注意:get查询不到结果或结果多于1条则报错 # 查询不到结果:User matching query does not exist. # 查询多于1条:get() returned more than one User -- it returned 2! 3. filter()方法 用法:User.objects.filter(属性名=值) 作用:可以查询空或1条或多条数据 (介于get和all) 返回值:Query对象 - 如果没有查询到数据返回为空的QuerySet eg: User.objects.filter(age=18) 4. count()方法 用法:User.objects.count() 作用:查询结果的数量 返回值:int类型 eg: User.objects.count() / User.objects.filter(age=18).count() 5. first()方法和last()方法: 用法:User.objects.first() / User.objects.last() 作用:获取结果中的第一条 或 最后一条数据 返回值: model对象6. exclude()方法: 用法:User.objects.exclude(属性名=值) 作用:查询相反的结果 -- 排除 返回值:QuerySet对象 eg: User.objects.exclude(age=18) 查询年龄不是18的数据
2.2 排序方法
# 默认按升序排列users = User.objects.order_by('age')print(users)# 降序排列users = User.objects.order_by('-age')print(users)# 先按年龄排序,年龄相同时按姓名排序users = User.objects.order_by('age','name')print(users)
补:限制操作
# 取结果集中的一部分数据users = User.objects.all()print(users[0])print(users[1:])# print(users[:-2])# print(users[-1])# 注意:QuerySet的用法和列表类似,但不支持负数下标# 如果的确想使用负数下标,可以先将QuerySet对象转为列表list(users)[-1]
2.3 条件查询
1. 在众多的查询方法中,适合做条件查询的有 get(id=1)、filter(age=18)、exclude(age=20)但是这些查询方法只能做等值查询2. 如果想做比较运算 < > <= >= ,则需要修改上述方法中的参数 filter(id>1)--错误 解决:将上述的四个符号替换为【lt gt lte gte】 users = User.objects.filter(id__gt=1) # 查询id>1print(users)users = User.objects.filter(age__gte=18) # 查询年龄大于等于18print(users)
2.4 模糊查询
# select * from t_user where name like '%z%';1. contains / icontains 包含 / 包含(对大小写不敏感)2. startswith / istartswith 以..开头3. endswith / iendswith 以..结尾eg: User.objects.filter(name__contains='a') # 查询名字包含a的用户
2.5 范围查询
# between .. and / in # select * from t_user where id in(1,3,5);1. in 在某个集合中 `id__in=(1,3,5)`2. range 在某个范围里 `id__range=(2,5)`eg: User.objects.filter(id__in=(1,3,5)) User.objects.filter(id__range=(2,5)) # 闭区间
2.6 空值查询
# 查询没有记录生日的用户users = User.objects.filter(birthday=None)print(users)# 查询没有记录生日的用户users = User.objects.filter(birthday__isnull=True)print(users)# select * from t_user where birthday is null / is not null# 查询记录了生日的用户users = User.objects.filter(birthday__isnull=False) # select * from t_user where birthday is null / is not nullprint(users)
2.7 日期查询 - 了解
- year / month 1-12 / day / hour / minute / second / week 一年第几周 / week_day 星期
# 需求:查询生日为2019年的用户users = User.objects.filter(birthday__year=2019)print(users)
2.8 映射查询(查询部分列)
# select * from t_user; - 查询所有列# select name,age from t_user; - 查询部分列User.objects.all() # 查询所有行及所有列User.objects.get(id=1) # id为1的这一行的所有列
- values(列名1,列名2…) # 返回值为QuerySet对象 元素为字典
users = User.objects.all()print(users) # 所有行所有列 返回值为QuerySet对象,但元素是Model对象# 查询全部列 返回值为QuerySet对象,但元素为字典dictusers = User.objects.values()print(users)# 只查询name和age列users = User.objects.values('name','age')print(users)print(users[0]['name'])
- only(列名1,列名2…) # 返回值为QuerySet对象 率先查询部分列
# 率先查询name和age 而其它的列需要的时候才会去查询 不需要则不查询 懒加载users = User.objects.only('name','age')print(users)print(users[0].name)print(users[0].age)print(users[0].salary)
2.9 聚合函数
# Max() / Min() / Sum() / Avg() / Count()from django.db.models import Max,Min,Sum,Avg,Countusers = User.objects.aggregate(Max('age'),Min('age'),Count('id'))print(users) # {'age__max': 25, 'age__min': 17, 'id__count': 5} users = User.objects.aggregate(x=Max('age'),n=Min('age'),c=Count('id'))print(users) # {'x': 25, 'n': 17, 'c': 5}
2.10 分组统计
语法: User.objects.values('age').annotate(Max('salary')) # 以年龄分组,查询每个年龄段的最高薪水
# 示例:emp = Employee.objects.filter(age__gte=1).values('age').annotate(Max('salary')).order_by('age')print(emp)print(result) # 以年龄分组,查询每个年龄段的最高薪水# 加Where条件# SQL: select max(salary),age from user where age>=18 group by age; result = User.objects.filter(age__gte=18).values('age').annotate(Max('salary')).order_by('age')print(result)# 加Having条件#查询年龄大于1的平均薪水大于5000的每个年龄段的平均薪水# SQL: select avg(salary),age from t_user where age >=18 group by age having avg(salary) > 15000;result = Employee.objects.filter(age__gte=1).values('age').annotate(ag=Avg('salary')).filter(ag__gte=5000).order_by('age')print(result)
2.11 F()和Q()函数
- F()函数:
User.objects.filter(id__gt=1) # id大于1的用户需求:查询id大于年龄的用户? User.objects.filter(id__gt=age) -- 错误解决: User.objects.filter(id__gt=F('age'))# 什么情况下需要使用F函数: 当查询条件中需要使用到另外的列(属性)时# eg: # blog create_time edit_time # 查询 被修改过的博客 # Blog.objects.filter(edit_time__gt=F('create_time'))
- Q()函数:
User.objects.filter(id__gt=2,age__gt=18) # 查询id大于2`且`年龄大于18的用户# 需求:查询id大于2 `或` 年龄大于18的用户解决:使用Q()函数 -- 表示或的关系# eg: users = User.objects.filter(Q(id__gt=2)|Q(age__gt=18)) print(users) # 表示非 ~ 波浪线 users = User.objects.filter(Q(id__gt=2)|~Q(age__gt=18)) print(users)
七、Raw-SQL
Raw-SQL: 原生SQL# 如果上述的查询并不能满足业务需求时,可以使用raw函数users = User.objects.raw('select * from modelapp_user')print(users)print(list(users))for user in users: print(user)