目录
昨日回顾
视图层 小白必会三板斧 1.JsonResponse 默认只能序列化字典类型 如果你想序列化其他json能够支持的格式 你需要加一个参数safe=False 当你的数据有中文的时候 如果你不想自动转码 你需要制定一个参数 来告诉 你需要动内部任何数据 借助于原生的json模块作为参考依据 json.dumps(obj,ensure_ascii=False) 阅读源码 发现 json_dumps_params = {} json.dumps(obj,cls,**json_dumps_params) 2.FBV与CBV FBV 路由 路由与视图函数内存地址 视图 函数 CBV 路由 看似 路由与类点方法 实在还是路由与函数的内存地址 视图 类 # 只要是处理前端请求的业务逻辑的视图函数 都需要加上request形参 from django.views import View class MyLogin(View): def get(self,request): return render(request,'login.html') def post(self,request): return HttpResponse('post请求') urs.py url(r'^login/',views.MyLogin.as_view()) # 1.函数名加括号执行优先级最高 # 2.该方法要么是普通函数 要么是绑定给类的方法 自动变形 url(r'^login/',views.view) # 内部源码 def as_view(cls,**kwargs): def view(...): self = cls(...) # 生成自己写的类的对象 return self.dispatch(...) # 一定要确认self到底是谁 # 然后一定要问你一句 对象查找属性和方法的顺序(慢) return view # 一旦用户敲了login 会自动加括号调用view函数 def dispatch(...) # 先判断当前请求方式在不在默认的八个请求方法内 if request.method.lower() in self.http_method_allowed: # 利用发射 获取到方法名对应的属性或者是方法 handler = getattr(self,request.method.lower(),error) else: # 提示报错 return handler(...) # 调用请求方法所对应的函数 如何给CBV加装饰器 django推荐你使用内置的模块来给CBV加装饰器 from django.utils.decorators import method_decorator # 1.直接在类上面装 method_decorator(wrapper,name='给类内部哪个方法装') # 2.直接在类的内部方法上装 method_decorator(wrapper) # 3.给类内部所有的方法都装 重写dispacth方法 method_decorator(wrapper) 模板层 1.模板语法的传值 python所有的基本数据类型全部支持 函数 会自动加括号调用 并且函数如果需要参数 那么模板语法不支持 类 会自动加括号实例化 产生对象 # 只要对象能够加括号调用 那么模板语法都会自动加括号 对象 直接传对象 显示的是对象的内容地址 你可以定义__str__来控制对象的展示 对象在html页面上可以调用绑定方法 2.过滤器的使用 语法结构 | 语法特点 会将|左边的数据当做第一个参数传入 :右边的数据当做第二个参数传入 |length |add |default:'默认值' # 类似于get方法和getattr方法 |slice:'2:9:2' |filesizeformat # 将数字格式化成表示容量大小的单位 |truncatechars # 截取字符 包含三个点 |truncatewords # 截取单词 按空格算单词数 不包含三个点 |safe # 告诉浏览器文本内容是安全的 如果有html标签 正常识别渲染即可 前后端取消转义的方法 前端 |safe 后端 from django.utils.safestring import mark_safe res = mark_safe('<a href='https://www.baidu.com'>点我</a>') # 也就意味着 html代码可以不再html文件内写 # 可以在后端写html代码 然后传递给前端 3.标签 一对逻辑 if判断 for循环 for循环内部有一个forloop对象 该对象可以判断for循环的开始和结束 first last 也可以帮你获取索引或者数据计数 counter0 counter for循环和if判断嵌套使用 {% for i in l %} {% if forloop.first %} 第一次操作 {% elif forloop.last %} 最后一次操作 {% else %} 中间操作 {% endif %} {% empty %} 如果for循环对象是空 执行empty内的逻辑 {% endfor %} with起别名 自定义过滤器 标签 inclusion_tag 1.先在应用下创建一个名字必须交templatetags文件夹 2.文件夹内部创建一个任意名称的py文件(mytag) 3.py文件内必须先写两句代码 from django.template impory Library register = Library() @regiser.filters(name='过滤器的名字') def index(): pass @register.simple_tag(name='标签名字') def index1(): ... @regisrer.inclusion_tag('html文件名',name='名字') def index2(): ... 如何使用自定义的 {% load 任意名称的py文件名mytag %} 模板的继承 当一个页面需要被频繁使用的时候 你可以考虑使用模板的继承 先通过block块划定后期可能需要修的区域 一个模板上通常一个有三块区域 css 一个 html内容 可以有多个 js 一个 如何使用模板 {% extends '模板的名字' %} {% block css %} 修改模板中css区域内容 {% endblock %} 模板的导入 {% include '你要想导入的html文件名' %}
模型层
1.配置测试脚本
1.1 应用下tests文件
直接在某一应用下的tests文件中书写代码(去manage.py拷贝前四行代码),然后手动写两行代码
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings") import django django.setup() -----------------------以上是配置代码------------------------ # 一定要等待测试脚本搭建完毕之后 才能导入django文件进行测试 from app01 import models '''测试代码'''
1.2 新建任意名称文件
一样书写以上代码,也可以
2. 数据的增删改查
2.1 创建数据
1.create方法
直接插入数据进行保存
book_obj = models.Books.objects.create(title='挪威的森林',price=123.23,pulish_date='2019-09-09') book_obj = models.Books.objects.create(title='人间失格',price=222.23,pulish_date=ctime) print(book_obj)
2.对象的save()方法
利用对象的绑定方法(实例化对象传值,利用对象的save方法创建保存)
book_obj = models.Books(title='我是猫',price=467.78,pulish_date='2019-02-22') book_obj.save()
queryset对象
filter
查询出来的结果是一个Queryset对象
只要是Queryset对象就可以无限制的调用Queryset方法
res = models.Books.objects.filter(pk=1).filter().filter().filter().filter()
只要是Queryset对象就可以通过
.query
查看当前结果对应的sql语句res.query SELECT `app01_books`.`id`, `app01_books`.`title`, `app01_books`.`price`, `app01_books`.`publish_date` FROM `app01_books` WHERE `app01_books`.`id` = 1
2.2 修改数据
pk
会自动查找到当前表的主键字段,后期都是使用pk指代主键字段
res = models.Books.objects.filter(pk=1) print(res) # <QuerySet [<Books: Books object>]>
1.利用Queryset方法update
models.Books.objects.filter(pk=2).update(price=333.33)
2.利用对象 get与filter
使用get与save,该方法不推荐使用
利用对象的修改 内部其实是重头到位将数据的所有字段都重新写一遍 book_obj = models.Books.objects.get(pk=3) book_obj.price = 888.88 book_obj.save() # 对象的保存
get与filter的区别
- filter获取到的是一个Queryset对象,类似一个列表
- get获取到的直接就是数据本身
- 当条件不存在的情况下
- filter不会报错直接返回一个空,推荐使用filter方法
- get则会直接报错
2.3 删除数据
1.利用Queryset方法 delete
models.Books.objects.filter(pk=3).delete()
2.利用对象的delete
方法
book_obj = models.Books.objects.get(pk=3) book_obj.delete()
2.4查询数据 十三门徒
orm语句的查询默认都是惰性查询,只有当你真正要使用到数据的时候才会执行orm语句
res0 = models.Books.objects.filter(pk=1) res1 = models.Books.objects res2 = models.Books res3 = models print(res0,type(res0)) # <QuerySet [<Books: Books object>]> <class 'django.db.models.query.QuerySet'> print(res1,type(res1)) # app01.Books.objects <class 'django.db.models.manager.Manager'> print(res2,type(res2)) # <class 'app01.models.Books'> <class 'django.db.models.base.ModelBase'> print(res3,type(res3)) # <module 'app01.models' from 'D:\\pycharm\\项目\\开课练习\\day53\\app01\\models.py'> <class 'module'>
自动打印对应sql语句
如果你想查看所有的orm语句内部对应的sql语句,你可以直接在配置文件setting中配置相应的代码即可
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
1.查询所有 all()
返回Queryset对象
res = models.Books.objects.all() print(res) # <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>
2.筛选 filter()
返回Queryset对象
相当于你原生sql语句里面的where,filter中多个参数之间是and关系
res = models.Books.objects.filter(pk=1) res = models.Books.objects.filter(pk=1,title='挪威的森林') print(res)
3.筛选 get()
获取数据对象本身
条件不存在会直接报错,并且查询条件必须唯一, 不推荐使用
res = models.Books.objects.get(pk=2) print(res) # Books object
4.取第一个 first()
获取数据对象
取Queryset对象中的第一个数据对象
res = models.Books.objects.filter(title='我是猫').first() print(res) # Books object print(res.title) # 我是猫
5.取最后 last()
获取数据对象
取Queryset对象中的最后一个数据对象
res = models.Books.objects.filter(title='我是猫').last() print(res) # Books object print(res.id) # 5
6.计数 count()
返回数字
统计数据的个数
res = models.Books.objects.count() print(res) # 4
7.获取指定字段值 values()
返回Queryset对象,列表套字典形式
获取数据对象中指定的字段的值,可以有多个
res = models.Books.objects.values('title','price') print(res) # <QuerySet [{'title': '挪威的森林', 'price': Decimal('123.23')}, {'title': '人间失格', 'price': Decimal('333.33')}, {'title': '我是猫', 'price': Decimal('888.88')}, {'title': '我是猫', 'price': Decimal('333.77')}]>
8.获取指定字段值 values_list()
返回Queryset对象,列表套元组形式
res = models.Books.objects.values_list('title') print(res) # <QuerySet [('挪威的森林',), ('人间失格',), ('我是猫',), ('我是猫',)]>
9.排序 order_by()
按照指定的字段进行排序,默认是升序,字段前添加-
符号降序排列
res = models.Books.objects.order_by('price') print(res) # <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>]>
语义明确 使用all().order_by('')
res = models.Books.objects.all().order_by('price')
降序
res = models.Books.objects.order_by('-price')
10.颠倒顺序 reverse()
颠倒的对象必须提前排序,与order_by联用,单独使用没有效果
res = models.Books.objects.all().order_by('price').reverse()
11.排除...之外 exclude()
返回Queryset对象
将拥有某一个字段排除出去
res = models.Books.objects.all().exclude(title='我是猫') print(res) # <QuerySet [<Books: Books object>, <Books: Books object>]>
12.判断查询结果是否有值 exists()
返回布尔值
res = models.Books.objects.filter(pk=100).exists() print(res) # False
13.对查询结果去重 distinct()
去重的前提是,必须完全相同( id不同也不行 ),可以与.values('')
配合使用
res = models.Books.objects.values('title') print(res) # <QuerySet [{'title': '挪威的森林'}, {'title': '人间失格'}, {'title': '我是猫'}, {'title': '我是猫'}]> res = models.Books.objects.values('title').distinct() print(res) # <QuerySet [{'title': '挪威的森林'}, {'title': '人间失格'}, {'title': '我是猫'}]>
2.5 神奇的双下划线方法
__gt
大于__lt
大于__gte
大于等于__lte
小于等于__lt
大于__in=['','']
取列表内固定参数__range=(,)
取范围内(头尾兼顾)- date字段
- 可以通过在其后加
__year,__month,__day
等来获取date的特点部分数据,指定获取年月日数据
- 可以通过在其后加
- 模糊查询
__startswith=''
查询以...开头__endswith=''
查询以...结尾__contains=''
查询中间有某一字符的(默认区分大小写)__icontains=''
前面加i
不区分大小写
mysql中的模糊查询
关键字like %:匹配任意个数的任意字符 _:匹配一位任意的字符
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and 类似的还有:startswith,istartswith, endswith, iendswith date字段还可以: models.Class.objects.filter(first_day__year=2017) date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据 # date # # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) # year # # Entry.objects.filter(pub_date__year=2005) # Entry.objects.filter(pub_date__year__gte=2005) # month # # Entry.objects.filter(pub_date__month=12) # Entry.objects.filter(pub_date__month__gte=6) # day # # Entry.objects.filter(pub_date__day=3) # Entry.objects.filter(pub_date__day__gte=3) # week_day # # Entry.objects.filter(pub_date__week_day=2) # Entry.objects.filter(pub_date__week_day__gte=2) 需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~
3. 多表查询
时间类型
DateField(auto_now_add=True) 时间类型 auto_now:每次修改数据的时候会自动更新数据(只会展示最新的一次修改时间) auto_now_add:当数据创建出来的时候,会自动将创建时间记录下来,适用于注册
1.表的创建与表关系的建立
from django.db import models # Create your models here. # 多表联查 # 书 class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField(auto_now_add=True) # 与出版社表关联 一对一 publish = models.ForeignKey(to='Publish') # 与作者多对多关系 authors = models.ManyToManyField(to='Author') # 出版社 class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) # 作者 class Author(models.Model): name = models.CharField(max_length=32) email = models.EmailField() # 与作业详情页一对一 author_detail = models.OneToOneField(to='AuthorDetail') # 作者详细 class AuthorDetail(models.Model): name = models.BigIntegerField() addr = models.CharField(max_length=64)
2.一对多字段数据的增删改查
2.1 增 create()
1.直接传表字段
传表里的实际字段,跟数据主键值
models.Book.objects.create(title='京华烟云',price=222.22,publish_id=1)
2.直接传对象
传给虚拟字段(外键名的虚拟字段),跟数据对象,(查找想要关联的对象传入)
publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='四世同堂',price=333.33,publish=publish_obj)
2.2 改 update()
1.直接传表字段
传表里的实际字段,跟数据主键值
models.Book.objects.filter(pk=1).update(publish_id=3)
2.直接放对象
传虚拟字段,跟数据对象
publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.filter(pk=1).update(publish=publish_obj)
2.3 删 delete()
删除有外键关系的表字段,默认是级联删除.
models.Publish.objects.filter(pk=1).delete()
3.多对多字段的增删改查
3.1 增 add()
add()方法能够向第三张表添加数据,既支持传数字,也支持传对象,两种都可以是多个
1.直接传数字
# 获取主键为2的书籍对象 book_obj = models.Book.objects.filter(pk=2).first() # 根据对象点第三张表的外键字段进行添加 book_obj.authors.add(1) # 给第三张表里的书籍绑定一个主键为1的作者 book_obj.authors.add(2,3) # 给第三张表里的书籍绑定主键为2和3的作者
2.传对象
# 获取主键为2的书籍对象 book_obj = models.Book.objects.filter(pk=2).first() # 获得author中主键为1,2的对象 author_obj = models.Author.objects.filter(pk=1).first() author_obj2 = models.Author.objects.filter(pk=2).first() # 书籍对象.authors进入第三张表中添加 book_obj.authors.add(author_obj,author_obj2 )
3.2 改 set(可迭代对象)
set()方法支持传多个,需要使用(可迭代对象)的方式,其原理是先删除再添加.
1.直接传数字
book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.set((1,)) book_obj.authors.set((2,3))
2.传对象
# 获取主键为2的书籍对象 book_obj = models.Book.objects.filter(pk=2).first() # 获得author中主键为1,2的对象 author_obj = models.Author.objects.filter(pk=1).first() author_obj2 = models.Author.objects.filter(pk=2).first() book_obj.authors.set((author_obj,author_obj2 ))
3.3 删 remove()
数字对象都可以,支持传多个,不需要迭代
1.直接传数字
book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.remove(1) book_obj.authors.remove(2,3)
2.传对象
book_obj = models.Book.objects.filter(pk=2).first() author_obj = models.Author.objects.filter(pk=1).first() author_obj2 = models.Author.objects.filter(pk=2).first() book_obj.authors.remove(author_obj) book_obj.authors.remove(author_obj,author_obj2 )
3.4 清空 clear()
删除某个数据在第三张表中的所有记录
将书籍主键为2的对象,在第三张表中清除掉 book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.clear()
4. 跨表查询
正反向查询
1.正向查询按 关系字段
正向查询 具有外键关系字段的一方向无关系的一表的查询是正向
2.反向查询按 表名小写+_set
反向查询 没有外键关系字段的表向有的表查询是反向
1.基于对象的跨表查询
子查询
正向查询
当正向查询 点击外键字段数据有多个的情况下,需要.all() app01.Author.None 即加.all()
题目
# 查询书籍主键为2的出版社名称 book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.publish) #出版社对象 print(book_obj.publish.name) #出版社名称
# 查询书籍主键为4的作者姓名 book_obj = models.Book.objects.filter(pk=4).first() print(book_obj.authors) # app01.Author.None print(book_obj.authors.all()) # 拿到主键为4的作者名列表
反向查询
反向查询时 一对一查询需要 '表名小写' 一对多,多对多查询需要 '表名小写_set.all()`
题目
# 查询出版社是东方出版社出的书籍 publish_obj = models.Publish.objects.filter(name='东方出版社').first() print(publish_obj.book_set.all())
# 查询作者是jason写的书 author_obj = models.Author.objects.filter(name='Jason').first() print(author_obj.book_set) # app01.Author.None print(author_obj.book_set.all()) # 写过的书籍
2.基于双下划线的跨表查询
联表操作
正向查询
写外键字段就相当于已经跨到了字段所关系的表中,你想要改表的哪个字段信息,只需要加__获取即可
题目
# 查询书籍主键为2的出版社名称 res = models.Book.objects.filter(pk=2).values('publish__name') print(res)
# 查询书籍pk为2的作者姓名和邮箱 res = models.Book.objects.filter(pk=2).values('authors__name','authors__email') print(res)
反向查询
反向查询 表名小写__字段 filter(表名小写__字段=值)
题目
# 获取书籍主键为2的出版社名称 res = models.Publish.objects.filter(book__pk=2).values('name') print(res)
# 获取书籍pk为2的作者姓名与邮箱 res = models.Author.objects.filter(book__pk=2).values('name','email') print(res)
连续跨表
# 获取书籍pk为2的作者的手机号 res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')