Django框架(五)
定义模型类
from django.db import models
# Create your models here.
class User(models.Model):
uid = models.AutoField(primary_key=True, verbose_name='编号')
name = models.CharField(max_length=32, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
join_time = models.DateTimeField(auto_now_add=True)
补充知识
# 1、存储时间格式数据:
models.DateField() # 日期字段:存储年月日
models.DateTimeField() # 日期字段:存储年月日时分秒
# 日期字段重要参数
auto_now : 每次更新操作数据的时候 该字段会自动将当前时间更新
auto_now_add : 在创建数据的时候会自动将当前创建时间记录下来,之后只要不人为的修改,那么时间就一直不变
# 2、pk关键字
作用:pk会自动查找到当前表的主键字段 指代的就是当前表的主键字段
优点:用了pk之后 你就不需要指代当前表的主键字段到底叫什么了(nid,pid,uid....)
# 3、.get()方法
作用:.get()方法可直接拿到当前用户对象
eg:
user_obj = models.User.objects.get(pk=1) # 直接拿到id=1的用户对象
相当于:
user_obj = models.User.objects.filter(pk=1).first()
# 但是不推荐使用get方法:因为一旦数据不存在那么使用该方法就会立刻报错,而使用filter方法如果数据不存在则返回空列表[]不会报错
执行数据库迁移命令
方式一:使用命令行
python manage.py makemigrations
python manage.py migrate
方式二:使用pycharm快捷方式
上方菜单栏里找到并点击Tools——Run manage.py Task,依次执行下面两条语句即可
makemigrations
migrate
使用pychram连接mysql
一、修改配置文件
二、连接mysql
编写测试脚本
当我们只想操作django中某一个py文件内容时,那么可以不用书写前后端交互的形式来判断运行结果是否正确,我们可以直接写一个测试脚本即可。
- 在我们创建应用的时候,会自动创建一个tests.py文件,我们可以在这里编写测试脚本。
from django.test import TestCase
# Create your tests here.
# 测试环境准备:去manage.py文件中拷贝下述代码到测试文件,然后自己配置两行,如下:
import os
# from app01 import models.py 不可以写在这里
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject1.settings')
import django
django.setup() # 相当于启动django
from app01 import models
print(models.User.objects.filter())
# 注意:如果测试的脚本需要用到模块,必须写在配置好的环境下面,不可在最外层导入模块使用
if __name__ == '__main__':
main()
- pycharm也提供了一种测试环境
单表操作
表的新增
# 方式一:
res = models.User.objects.create(name='jack',age=19,register_time='2000-1-2')
print(res) # 返回值为当前被创建对象本身
# 方式二:
import datetime
ctime = datetime.datetime.now() # 当前时间
user_obj = models.User(name='tom',age=10,register_time=ctime) # 也可存入一个日期对象
user_obj.save()
表的删除
# 方式一:
res = models.User.objects.filter(pk=2).delete()
print(res) # 返回值为当前sql语句影响的行数(到底删了几行)
# 方式二:
user_obj = models.User.objects.filter(pk=1).first() # 拿到当前用户对象
user_obj.delete() # 用户对象也有delete方法
表的修改
# 方式一:
models.User.objects.filter(pk=4).update(name='tom2222') # 匹配到id=4的记录并只修改name属性
# 方式二:
user_obj = models.User.objects.get(pk=4)
user_obj.name = 'tom3333'
user_obj.save()
ORM常见查询关键字
1.all()
# 查询所有数据
res = models.User.objects.all() # 括号内不可添加筛选条件
print(res)
# 结果:<QuerySet [<User: 对象:jack>, <User: 对象:tom>]>
2.filter()
# 带有过滤条件的查询
res = models.User.objects.filter(pk=2) # 括号内可添加筛选条件
print(res)
# 结果:<QuerySet [<User: 对象:tom>]>
3.get()
# 直接拿数据对象,但是条件所匹配的数据不存在则直接报错
res = models.User.objects.get(pk=2)
print(res) # 结果 对象:tom
res1 = models.User.objects.get(pk=3)
print(res1) # 结果 报错
4.first()
# 拿queryset里面的第一个元素
res = models.User.objects.filter().first()
print(res)
# 结果:对象:jack
5.last()
# 拿queryset里面的最后一个元素
res = models.User.objects.filter().last()
print(res)
# 结果:对象:tom
6.values()
# 可指定获取的字段,返回结果可以看作是列表套字典的形式
# 拿到所有用户的信息
res = models.User.objects.values()
print(res)
# 结果:<QuerySet [{'id': 1, 'name': 'jack', 'age': 19, 'register_time': datetime.date(2000, 1, 2)}, {'id': 2, 'name': 'tom', 'age': 10, 'register_time': datetime.date(2022, 2, 26)}]> # 列表套字典的形式
eg:
# 1、只拿用户的名字
res = models.User.objects.values('name')
print(res)
# 结果:<QuerySet [{'name': 'jack'}, {'name': 'tom'}]>
# 2、只拿用户的名字和年龄
res = models.User.objects.values('name','age')
print(res)
# 结果:<QuerySet [{'name': 'jack', 'age': 19}, {'name': 'tom', 'age': 10}]>
相当于sql语句:select name,age from user
7.values_list()
# 同样可以指定需要获取的字段
# 但返回结果可以看作是列表套元组的形式
res = models.User.objects.values()
print(res)
# 结果:<QuerySet [(1, 'jack', 19, datetime.date(2000, 1, 2)), (2, 'tom', 10, datetime.date(2022, 2, 26))]>
8.distinct()
# 去重
# 注意:去重一定要是一摸一样的数据(一定要考虑主键),一个对象如果包含主键的话永远去不了重复数据
res = models.User.objects.filter().distinct()
print(res) # 查所有:无意义,因为包含主键
res1= models.User.objects.values('name').distinct()
print(res1) # 按照name字段去重
# 结果:
# <QuerySet [<User: 对象:jack>, <User: 对象:tom>, <User: 对象:jack>, <User: 对象:gary>]>
# <QuerySet [{'name': 'jack'}, {'name': 'tom'}, {'name': 'gary'}]>
9.order_by()
# 排序
.order_by('age') # 默认升序
.order_by('-age') # 降序在参数前加一个-
# eg:
res1 = models.User.objects.values('age').order_by('age')
print(res1) # 升序
res = models.User.objects.order_by('-age')
print(res) # 降序
10.reverse()
# 反转
# 前提:数据已经排序了,如果没排序是不支持反转的,必须提前排序过。
order_by().reverse() # 通常情况下跟order_by联合使用
# eg:
res = models.User.objects.filter().reverse()
print(res)
res1 = models.User.objects.order_by('age')
res2 = models.User.objects.order_by('age').reverse()
print(res2)
11.count()
# 统计当前数据的个数
res = .count()
# eg:
res = models.User.objects.filter().count()
print(res) # 统计所有数据对象的个数
res = models.User.objects.values('name').distinct().count()
print(res) # 按照name去重之后统计数据个数
# 结果:
4
3
12.exclude()
# .exclude() # 排除(括号内匹配成功)之外的数据
# eg:
res = models.User.objects.exclude(name='jack')
print(res)
# 查询name = 'jack'之外的数据
13.exists()
# 判断是否存在 返回的是布尔值
# 作用不大:因为数据本身就存在布尔值
# eg:
res = models.User.objects.filter(pk=1).exists()
print(res)
res1 = models.User.objects.filter(pk=200)
print(res1)
res2 = models.User.objects.filter(pk=200).exists()
print(res2)
# 结果:
True
<QuerySet []>
False
14.raw()
执行SQL语句
还可以借助于模块
from django.db import connection
cursor = connection.cursor()
cursor.execute("insert into hello_author(name) VALUES ('郭敬明')")
cursor.execute("update hello_author set name='韩寒' WHERE name='郭敬明'")
cursor.execute("delete from hello_author where name='韩寒'")
cursor.execute("select * from hello_author")
cursor.fetchone()
cursor.fetchall()
ORM双下划线查询方法
比较运算
# 关键字:
大于: __gt
小于: __lt
大于等于: __gte
小于等于: __lte
# 举例:
res = models.User.objects.filter(age__gt=20)
print(res) # 年龄大于20
res1 = models.User.objects.filter(age__lt=30)
print(res) # 年龄小于30
res2 = models.User.objects.filter(age__gte=19)
print(res2) # 年龄大于等于19
res3 = models.User.objects.filter(age__lte=30)
print(res3) # 年龄小于等于30
在某一数据集内
# 关键字:__in=['数据集']
# 举例:
res = models.User.objects.filter(age__in=[10,20,30,40])
print(res)
在某一范围内
# 关键字:__range=[]
# 举例:
res = models.User.objects.filter(age__range=[19,40])
print(res)
模糊查询
# 关键字:__contain='' 区分大小写
__icontain='' 不区分大小写
# 举例:
res = models.User.objects.filter(name__contains='k')
print(res)
res1 = models.User.objects.filter(name__icontains='k')
print(res1)
以什么开头/结尾
# 关键字:__startswith='' 以什么开头
__endswith='' 以什么结尾
__istartswith='' 不区分大小写
__iendswith='' 不区分大小写
按照日期查询
# 关键字:
__month='1' # 按照月份取
__year='2020' # 按照年份
__day='29' # 按照天筛选
__weekday='' # 按照日期
# 举例:
res = models.User.objects.filter(register_time__month='01')
print(res)
res1= models.User.objects.filter(register_time__day='02')
print(res1)
res2= models.User.objects.filter(register_time__week_day='02')
print(res2)
res3 = models.User.objects.filter(register_time__year='2022')
print(res3)
res4 = models.User.objects.filter(register_time__year='2022',register_time__month='02')
print(res4)
查看ORM底层SQL语句
# .query方法
.query方法可查看内部封装的sql语句
但是使用该方法查看sql语句的方式,只能用于queryset对象属性
只有返回结果为queryset对象才能够使用
eg:
res1 = models.User.objects.filter()
print(res1.query)
res = models.User.objects.get(name='jack')
print(res.query)
# 解决:所有的sql语句都能查看
# 将下述代码放到配置文件里
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
ORM外键字段的创建
一对多
ORM中外键字段建在多的一方 models.ForeignKey()
会自动添加_id后缀
多对多
ORM中有三种创建多对多字段的方式 models.ManyToManyField()
方式1:直接在查询频率较高的表中填写字段即可 自动创建第三张关系表
方式2:自己创建第三张关系表
方式3:自己创建第三张关系表 但是还是要orm多对多字段做关联
一对一
ORM中外键字段建在查询频率较高的表中 models.OneToOneField()
会自动添加_id后缀
django1.X 针对 models.ForeignKey() models.OneToOneField()不需要on_delete
django2.X 3.X 则需要添加on_delete参数
ORM多表操作
多表操作前期准备
models.py
class Book(models.Model):
name = models.CharField(max_length=32,verbose_name='书名')
price = models.DecimalField(max_digits=8,decimal_places=2,verbose_name='价格')
publish_date = models.DateTimeField(auto_now_add=True,verbose_name='出版时间')
publish = models.ForeignKey('Publish') # 一对多
authors = models.ManyToManyField('Author') # 多对多
class Publish(models.Model):
name = models.CharField(max_length=32,verbose_name='出版社名字')
addr = models.CharField(max_length=32,verbose_name='出版社地址')
class Author(models.Model):
name = models.CharField(max_length=32,verbose_name='作者名字')
age = models.IntegerField(verbose_name='作者年龄')
author_detail = models.OneToOneField('AuthorDetails') # 一对一
class AuthorDetails(models.Model):
phone = models.BigIntegerField(verbose_name='作者电话')
addr = models.CharField(max_length=32,verbose_name='作者地址')
一对多外键增删改查
# 一对多外键增加数据
# 方式一:直接写实际字段
models.Book.objects.create(name='红楼梦',price=111.11,publish_id=1)
# 方式二:虚拟字段
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(name='三国演义',price=22.5,publish=publish_obj)
# 一对多外键删除数据
models.Pulish.objects.filter(pk=1).delete()
# 删除记录是级联删除的,所以对应的外键字段一会直接删除,取消关联关系
# 一对多外键修改数据
# 方式一:直接写实际字段
models.Book.objects.filter(pk=1).update(publish_id=2)
# 方式二:虚拟字段
publist_obj = models.Publish.objects.filter(pk=3).first()
models.Book.objects.filter(pk=2).update(publish=publist_obj)
多对多外键增删改查
# 多对多的增删改查其实就是在操作第三张虚拟表
# 先思考一个问题,如何添加作者
# 这张表不是我们自己创建的是系统帮助我们创建的,所以我们根本不能通过models的方法(.)到这张表
# 这里就要通过对象(.)外键的方式找到第三张表
# 多对多表关系的增加:
# 关键字:.add(主键值)
# 方式一:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1)
book_obj.authors.add(2,3) # 增加多个
# 方式二:
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1,author_obj2) # 增加多个
# 多对多表关系的删:
# 关键字:.remove(主键值)
# 方式一:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(2,3) # 同样支持多条数据同时删除
# 方式二:对象
book_obj1 = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj1.authors.remove(author_obj1,author_obj2)
# 多对多表关系的修改
# 关键字:set()
# 方式一:
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2,3]) # 同样支持多条数据同时修改
# 方式二:对象
book_obj1 = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj1.authors.set([author_obj1,author_obj2])
# 注意:set关键字括号内必须填写一个可迭代对象(列表或者元组)
# 多对多表关系的清空(清空在第三中某个书籍与作者的绑定关系)
# 关键字:clear() # 括号内不要加任何参数
正反向的概念
正反向的概念核心就在于外键字段在谁手上
正向查询
通过书查询出版社 外键字段在书表中
反向查询
通过出版社查询书 外键字段不在出版社表中
ORM跨表查询口诀>>>:正向查询按外键字段 反向查询按表名小写
基于对象的跨表查询(子查询)
# 查找主键值为1的书的出版社名字和出版社地址(正向)
book_obj = models.Book.objects.filter(pk=1).first() # 先拿到主键为1的书籍对象
res = book_obj.publish # 拿到外键字段所对应关系表中的对象
print(res) # 对应出版社的对象
print(res.name) # 出版社名字
print(res.addr) # 出版社地址
# 查询书籍主键为2的作者(正向)
book_obj = models.Book.objects.filter(pk=2).first()
res = book_obj.authors #
print(res)
# 我们发现返回了一个:app01.Author.None
# 注意这个返回结果是一个标志性的问题:在当返回结果可能为多个的时候(一本书可以由多名作者编写(多对多的表关系)必须加关键字.all())
# # 查询书籍主键为2的作者(正向)
book_obj = models.Book.objects.filter(pk=2).first()
res = book_obj.authors.all()
print(res)
print(res[0].name) # 因对象有多个所以要通过索引取值拿到单独的对象
print(res[1].name)
# 查询作者gary的电话号码(正向)
author_obj = models.Author.objects.filter(name='gary').first()
print(author_obj)
res = author_obj.author_detail
print(res)
print(res.phone)
print(res.addr)
# 查询是南方出版社出版的书(无外键字段(反向))
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
res = publish_obj.book
print(res)
# 反向查询上边有提到需要加入_set
# 查询是南方出版社出版的书(无外键字段(反向))
publish_obj = models.Publish.objects.filter(name='南方出版社').first()
res = publish_obj.book_set.all() # 并且使用到.all()方法
print(res)
# 5.查询作者是jason写过的书
author_obj = models.Author.objects.filter(name='jason').first()
res = author_obj.book_set.all()
print(res)
# 6.查询手机号是110的作者姓名
authorsetails_obj = models.AuthorDetails.objects.filter(phone='110').first()
res1 = authorsetails_obj.author
print(res1)
总结:
# 基于对象
反向查询的时候
当你的查询结果可能有多个的时候 就必须加_set.all()
当你的结果只能有一个的时候 不需要加_set.all()
基于双下划线的跨表查询(连表操作)
# 同样遵循
# 正向查询按字段
# 反向查询按表名小写
# 查询作者gary的手机号(必须用一行代码展示)
res = models.Author.objects.filter(name='gary').values('author_detail__phone','name')
print(res)
# 利用values方法查询
注意:此时Author为基表可通过values方法直接查到该表的属性值
# 反向:(不允许.Author)
res = models.AuthorDetails.objects.filter(author__name='gary').values('phone','author__name')
print(res)
# 查询书籍主键为1的出版社的名称和书的名称
res = models.Book.objects.filter(pk=1).values('name','publish__book')
print(res)
# 方式二:反向
res = models.Publish.objects.filter(book__id='1').values('name','book__name')
print(res)
# 3.查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)
# 方式二:反向
res = models.Author.objects.filter(book__id=1).values('name')
print(res)
# 查询书籍主键是1的作者的手机号
# 注意:这道题涉及到三张表
# 思路:通过书籍查作者,再通过作者查作者详情
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')