内容导航
内容详细
django路由层
1.路由匹配
django2.X及以上 path第一个参数些什么就匹配什么
django1.X第一个参数是正则表达式
无论匹配什么版本django都自带加斜杠后缀的功能 也可以取消
配置文件中APPEND_SLASH = False 取消加斜杠后缀
2.转换器
正常情况下很多网站都会有很多相似的网址 如果我们每一个都单独开设路由不太合理 django2.X及以上版本路由动态匹配有转换器(五种):
str :匹配除路径分隔符外的任何非空字符串。
int :匹配0 或任何正整数。
slug:匹配任意一个由字母或数字组成的字符串。
uuid:匹配格式化后的UUID。
path:能够匹配完整的URL路径
ps:还支持自定义转换器(自己写正则表达式匹配更加细化的内容)
path('index/<str:info>/' , views.index_func)
path('index/<>str:info/<int:id>/' , views.index_func)
3.正则匹配
django2.X及以上版本又re_path 第一个参数是正则
匹配的本质是只要第一个正则表达式能够从用户输入的路由中匹配到数据就算匹配成功会立刻停止路由层其他的匹配直接执行对应的视图函数
re_path('^test/$' , views.test)
django1.x路由匹配使用的是url() 功能与django2.x及以上的re_path()一致
4.正则匹配的无名有名分组
无名分组
re_path('^test/(\d{4})/' , views.test)
会将括号内正则匹配到的内容当做位置参数传递给视图函数
有名分组
re_path('^test/(?P<year>\d{4})' , views.test)
会将括号内正则匹配到的内容当作关键字参数传递给视图函数
5.反向解析
通过一个名字可以反向解析出一个结果 该结果可以访问到某个对应的路由
基本使用
1. 路由匹配关系起别名
path('login001/' , views.login, name='login_view' )
2. 反向解析语法
html页面上模板语法 {% url 'login_view' %}
后端语法 reverse('login_view' )
动态路由的反向解析
path('func1/<str:others>' , views.func1_func, name='func1_view' )
html页面上反向语法{% url 'func1_view' 'jason' %}
后端语法 reverse('func1_view' , args=('嘿嘿嘿' ,))
6.路由分发
django支持每个应用都可以有自己独立的路由层、静态文件、模板层。基于该特性多人开发项目就可以完全解耦合,之后利用路由分发还可以整合到一起
多个应用都有很多路由与视图函数的对应关系 这个时候可以拆分到各自的路由层中
使用路由分发之前 总路由直接干路由与视图函数的匹配的活
path('index/' ,index)
使用路由分发之后 总路由只按照应用名分配匹配方向
path('app01/' , include('app01.urls' ))
'''应用文件内创建urls.py为子路由的路由层'''
7.名称空间
路由分发之后 针对相同的别名能否自动反向解析出不同的应用前缀
默认情况下是无法直接识别应用前缀的
如果想要正常识别区分有两种方式:
方式1 :名称空间
总路由
path('app01/' , include(('app01.urls' ,'app01' ), namespace='app01' )),
path('app02/' , include(('app02.urls' , 'app02' ), namespace='app02' )),
反向解析
reverse('app01:index_view' )
reverse('app01:index_view' )
方式2 :别名不冲突即可
多个应用别名不冲突可以用应用名作为别名的前缀
path('index/' ,view.index, name='app01_index_view' )
path('index/' ,view.index, name='app02_index_view' )
8.虚拟环境
项目1 需要使用:django1.11 python38
项目2 需要使用:django2.22 pymysql requests python38
项目3 需要使用:django3.22 request_html flask urllib3 python38
实际开发项目中我们只会给项目配备所需的环境,不需要的一概不配!!!
虚拟环境:能够针对相同版本的解释器创建多个分身 每个分身可以有自己独立的环境
pycharm创建虚拟环境:(每创建一个虚拟环境就相当于重新下载了一个全新的解释器)
命令行的方式: python -m venv pyvenv38
注意:python命令此处不支持多版本共存的操作 python27 python36 python38
激活
activate
关闭
deactivate
pip install --index-url http://mirrors.aliyun.com/pypi/simple/ django==1.11 .11 --trusted-host mirrors.aliyun.com
django视图层
1.视图层之必会三板斧
用来处理请求的视图函数都必须返回HttpResponse对象
class HttpResponse :
pass
return HttpResponse()
def render ():
return HttpResponse()
return render()
def redirect ():
redirect_class = 类(祖先有个类是HttpResponse)
return redirect_class()
return redirect()
2.JsonResponse对象
from django.http import JsonResponse
def index_func (request ):
return HttpResponse('嘿嘿嘿' )
返回给浏览器一个json格式的字符串
user_dict = {'name' :'jason老师' ,'age' :18 }
1. 第一种方式
import json
user_json = json.dumps(user_dict, ensure_ascii=False )
return HttpResponse(user_json)
2. 第二种方式
return JsonResponse(user_dict)
return JsonResponse(user_dict, json_dumps_params={'ensure_ascii: False' })
ps: 以后写代码很多时候可能需要参考源码及所学知识扩展功能
class JsonResponse ():
def __init__ (self,data,json_dumps_params=None ):
json.dumps(data,**json_dunps_params)
JsonResponse主要序列化字典 针对非字典的其他可以被序列化的数据需要修改safe参数为False
3.request对象获取文件
form表单携带文件类型的数据需要做到以下几点
1. method必须是post
2. enctype必须是multipart/form-data
django后端需要通过request.FILES获取文件类型的数据
4.视图层之FBV与CBV
FBV
基于函数的视图
def index (request ):return HttpResponse对象
CBV
基于类的视图
from django import views
class MyLoginView (views.View):
def get (self, request ):
return HttpResponse('from CBV get function' )
def post (self, request ):
return HttpResponse('from CBV post function' )
urls文件中:path('login/' , views.MyLoginView.as_view())
5.CBV源码剖析(重要)
1. 从CBV的路由匹配切入
path('login/' , views.MyLoginView.as_view())
1. 类名点名字(名字的查找问题)
2. 类名点名字并加括号调用(静态方法、绑定给类的方法)
2. 函数名加括号执行优先级最高 项目已启动就会自动执行as_view
path('login/' ,views.view)
3. 浏览器地址栏访问login路由需要执行view函数
1. 产生我们自己编写的类的对象
2. 对象调用dispatch方法(注意查找顺序)
4. 研究父类中的dispatch方法
获取当前请求方法并转小写 之后利用反射获取类中对应的方法并执行
class View :
@classmethod
def as_view (cls, **initkwargs ):
def view (request, *args, **kwargs ):
self = cls(**initkwargs)
return self.dispatch(request, *args, **kwargs)
def dispatch (self, request, *args, **kwargs ):
handler = getattr (self, request.method.lower())
return handler(request, *args, **kwargs)
django模板层
1.模板语法传值
"""
{{}}: 主要与数据值相关
{%%}: 主要与逻辑相关
django的模板语法是自己写的 跟jinja2不一样
1.针对需要加括号调用的名字 django模板语法会自动加括号调用你只需要写名字就行
2.模板语法的注释前端浏览器是无法查看的{##}
"""
1. 模板语法传值
return render(request, 'demo02.html' , {'n1' : name, 'a1' :age})
return render(request, 'demo02.html' , locals ())
2. 模板语法传值特性
1. 基本数据类型正常展示
2. 文件对象也可以展示并调用方法
3. 函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
4. 类名也会自动加括号调用
5. 对象则不会
ps:总结针对可以加括号调用的名字模板语法都会自动加括号调用
3. 模板语法之过滤器(内置函数)
{{i|add:10 }} |add:
{{l|length}} |length
{{s|slice :'1:4' }} |slice :''
{{s|truncatechars:5 }} |truncatechars:
{{s|truncatewords:1 }} |truncatewords:
{{ctime|date:'Y年-m月-d日 H:i:s' }}
{{file_size|filesizeformat }}
{{h1|safe}}
2.模板层之标签
{% if 条件1 (可以自己写也可以用传递过来的数据) %}
<p>今天又是周三</p>
{% elif 条件2 (可以自己写也可以用传递过来的数据) %}
<p>百日冲刺</p>
{% else %}
<p>没多少时间了!</p>
{% endif %}
{% for k in t1 %}
{% if forloop.first %}
<p>这是我的第一次循环{{ k }}</p>
{% elif forloop.last %}
<p>这是我的最后一次循环{{ k }}</p>
{% else %}
<p>这是中间循环{{ k }}</p>
{% endif %}
{% empty %}
<p>你给我传的数据是空的无法循环取值(空字符串、空列表、空字典)</p>
{% endfor %}
django模板语法取值操作>>>:只支持句点符
句点符既可以点索引也可以点键
{{ d1.hobby.2 .a1 }}
{% with d1.hobby.2 .a1 as h %} 复杂数据获取之后需要反复使用可以起别名
<a href="" >{{ h }}</a>
{% endwith %}
3.自定义过滤器、标签及inclusion_tag(了解)
"""
如果想要自定义一些模板语法 需要先完成下列的三步走战列
1.在应用下创建一个名字必须叫templatetags的目录
2.在上述目录下创建任意名称的py文件
3.在上述py文件内先编写两行固定的代码
from django import template
register = template.Library()
"""
@register.filter(name='myadd' )
def func1 (a, b ):
rerurn a + b
{% load mytags %}
<p>{{ i|myadd:1 }}</p>
@register.simple_tag(name'mytag' )
def func2 (a, b, c, d, e ):
return f'{a} -{b} -{c} -{d} -{e} '
{% load mytags %}
{% mytag 'jason' 'kevin' 'oscar' 'tony' 'lili' %}
@register.inclusion_tag('menu.html' , name='mymenu' )
def func3 (n ):
html = []
for i in range (n):
html.append('<li>第%s页</l1>' %i)
return locals ()
{% load mytags %}
{% mymenu 20 %}
4.母版的继承与导入
母版的继承(重要)
多个页面有很多相似的地方 我们可以采取下列方式
方式1 :传统的复制粘贴
方式2 :母版的继承
1. 在母版中使用block划定子板后可以修改的区域
{% block 区域名称 %}
{% endblock %}
2. 子版继承母版
{% extends 'home.html' %}
{% block 区域名称 %}
子板自己的内容
{% endblock %}
ps:母版中至少应该有三个区域
页面内容区、css样式区、js代码区
补充:子板也可以继续使用母版的内容
{{ block.super }}
母版的导入(了解)
将某个html的部分提前写好 之后很多html页面都相适应就可以导入
{% include 'myform.html' %}
django模型层
1.模型层之前期准备
1. 自带的sqlite3数据库对事件字段不敏感 有时候会展示错乱 所以我们习惯切换成常见的数据库比如MySQL django orm并不会自动帮你创建库 所以需要提前准备好
2. 单独测试django某个功能层
默认不允许单独测试某个py文件 如果想要测试某个py文件(主要是models.py)
测试环境1 :pycharm提供的python console
测试环境2 :自己搭建(自带的test或者自己创建)
1. 拷贝manage.py前四行
2. 自己再加两行
import django
django.setup()
3. django ORM底层还是SQL语句 我们是可以查看的
如果我们手上是一个QuerySet对象 那么可以直接点query查看SQL语句
如果想查看所有ORM底层的SQL语句也可以在配置文件添加日志记录
在settings.py中添加以下代码
LOGGING = {
'version' : 1 ,
'disable_existing_loggers' : False ,
'handlers' : {
'console' :{
'level' :'DEBUG' ,
'class' :'logging.StreamHandler' ,
},
},
'loggers' : {
'django.db.backends' : {
'handlers' : ['console' ],
'propagate' : True ,
'level' :'DEBUG' ,
},
}
}
2.ORM常用关键字
1. create() 创建数据并直接获取当前创建的数据对象
res = models.User.objects.create(name='guts' ,age=22 )
print (res)
2. filter () 根据条件筛选数据 结果是QuerySet [数据对象1 ,数据对象2 ]
res = models.User.objects.filter ()
res = models.User.objects.filter (name='guts' )
res = models.User.objects.filter (name='guts' ,age=22 )
3. first() last() QuerySet支持索引取值但是只支持正数 并且ORM不建议你使用索引
res = models.User.objects.filter ()[1 ]
res = models.User.objects.filter (pk=100 ).first()
res = models.User.objects.filter (pk=100 ).last()
4. update() 更新数据(批量更新)
models.User.objects.filter ().update()
models.User.objects.filter (id =1 ),update()
5. delete() 删除数据(批量删除)
models.User.objects.filter ().delete()
models.User.objects.filter (id =1 ).delete()
6. all () 查询所有数据 结果是QuerySet [数据对象1 ,数据对象2 ]
res = models.User.object .all ()
7. values() 根据指定字段获取数据 结果是QuerySet [{},{},{}]
res = models.User.objects.all ().values('name' )
res = models.User.objects.filter ().values()
res = models.User.objects.values()
8. values_list() 根据指定字段获取数据 结果是QuerySet [(),(),()]
res = models.User.objects.all ().values_list('name' ,'age' )
9. distinct() 去重 数据一定要一模一样才可以 如果有主键肯定不行
res = models.User.objects.values('name' ,'age' ).distinct()
10. order_by() 根据指定条件排序 默认是升序 字段前面加符号就算降序
res = models.User.objects.all ().order_by('age' )
print (res)
11. get() 根据条件筛选数据并直接获取到数据对象 一旦条件不存在会直接报错
不建议使用
res = models.User.objects.get(pk=1 )
print (res)
res = models.User.objects.get(pk=100 ,name='guts' )
12. exclude() 取反操作
res = models.User.object .exclude(pk=1 )
print (res)
13. reverse() 颠倒顺序(被操作的对象必须是已经排过序的才可以)
res = models.User.object .all ()
res = models.User.object .all ().order_by('age' )
res1 = models.User.object .all ().order_by('age' ).reverse()
print (res, res1)
14. count() 统计结果集中数据的个数
res = models.User.objects.all ().count()
print (res)
15. exists() 判断结果集中是否含有数据 如果有则返回True 没有则返回False
res = models.User.objects.all ().exists()
print (res)
res1 = models.User.objects.filter (pk=100 ).exists()
print (res1)
3.ORM执行SQL语句
有时候ORM的操作效率可能偏低 我们是可以自己编写SQL的
方式1 :
models.User.objects.raw('select * from app01_user;' )
方式2 :
from django.db import connection
cursor = connection.cursor()
cursor.execute('select name from app01_user;' )
print (cursor.fetchall())
4.神奇的双下划线查询
"""
只要还是queryset对象就可以无限制的点queryset对象的方法
queryset.filter().values().filter().values_list().filter()...
"""
res = models.User.objects.filter (age__gt=18 )
res = models.User.objects.filter (age__lt=38 )
res = models.User.objects.filter (age__gte=18 )
res = models.User.objects.filter (age__lte=30 )
res = models.User.objects.filter (age__in=(18 ,28 ,38 ))
res = models.User.objects.filter (age__range=(18 ,38 ))
res = models.User.objects.filter (name__contains='j' )
res = models.User.objects.filter (name__icontains='j' )
res = models.User.objects.filter (register_time__year=2022 )
'''针对django框架的时区问题 是需要配置文件中修改的 后续bbs讲解'''
5.ORM外键字段的创建
'''
复习MySQL外键关系
一对多
外键字段建在多的一方
多对多
外键字段建在第三张关系表
一对一
建在任何一方都可以 但是建议建在查询频率较高的表中
ps:关系的判断可以采用换位思考原则 熟练了之后可以瞬间判断
'''
1. 创建基础表(书籍表、出版社表、作者表、作者详情)
2. 确定外键关系
一对多 ORM与MySQL一致 外键字段建在多的一方
多对多 ORM比MySQL有更多变化
1. 外键字段可以直接建在某张表中(查询频率较高的)
内部会自动帮你创建第三张表关系
2. 自己创建第三张表关系并创建外键字段
详情后续讲解
一对一 ORM与MySQL一致 外键字段建在查询频率较高的一方
3. ORM创建
针对一对多和一对一同步到表中之后会自动加_id 的后缀
publish = models.ForeignKey(to='Publish' ,on_delete=models.CASCADE)
author_detail = models.OneToOneField(to='AuthorDetail' ,on_delete=models.CASCADE)
针对多对多 不会在表中有展示 而是创建第三张表
authors = models.ManyToManyField(to='Author' )
6.外键字段相关操作
models.Book.objects.create(title='三国演义' ,price=888.88 ,publish_id=1 )
models.Book.objects.create(title='人性的弱点' ,price=777.77 ,publish_id=1 )
publish_obj = models.Publish.objects.filter (pk=1 ).first()
models.Book.objects.create(title='水浒传' ,price=555.66 ,publish=publish_obj)
'''一对一与一对多 一致'''
既可以传数字也可以传对象
book_obj = models.Book.objects.filter (pk=1 ).first()
book_obj.authors.add(1 )
book_obj.authors.add(2 ,3 )
book_obj = models.Book.objects.filter (pk=4 ).first()
author_obj1 = models.Author.objects.filter (pk=1 ).first()
author_obj2 = models.Author.objects.filter (pk=2 ).first()
book_obj.authors.add(author_obj1)
book_obj.authors.add(author_obj1,author_obj2)
book_obj = models.Book.objects.filter (pk=1 ).first()
book_obj.authors.set ((1 ,3 ))
book_obj.authors.set ([2 ,])
author_obj1 = models.Author.objects.filter (pk=1 ).first()
author_obj2 = models.Author.objects.filter (pk=2 ).first()
book_obj.authors.set ((author_obj1,))
book_obj.authors.set ((author_obj1,author_obj2))
book_obj.authors.remove(2 )
book_obj.authors.remove(author_obj1,author_obj2)
book_obj.authors.clear()
add()\remove() 多个位置参数(数字 对象)
set () 可迭代对象(元组 列表) 数字 对象
clear() 清空当前数据对象的关系
7.ORM跨表查询
"""
复习MySQL跨表查询的思路
子查询
分步操作:将一条SQL语句用括号括起来当作另一条SQL语句的条件
连表操作
先整合多张表之后基于单表查询即可
inner join 内连接
left join 左连接
right join 右连接
"""
正反向查询的概念(重要)
正向查询
由外键字段所在的表数据查询关联的表数据 正向
反向查询
没有外键字段的表数据查询关联的表数据 反向
ps:正反向的核心就是看外键字段在不在当前数据所在的表中
ORM跨表查询的口诀(重要)
正向查询按外键字段
反向查询按表名小写
8.基于对象的跨表查询
author_obj = models.Author.objects.filter (name='jason' ).first()
print (author_obj.author_detail.phone)
author_detail_obj = models.AuthorDetail.objects.filter (phone=110 ).first()
print (author_detail_obj.author)
print (author_detail_obj.author.name)
9.基于上下划线的跨表查询
'''基于双下划线的跨表查询'''
res = models.AuthorDetail.objects.filter (phone=110 ).values('phone' , 'author__name' )
print (res)
10.进阶操作
res = models.Author.objects.filter (author_detail__phone=110 ).values('name' )
print (res)
"""
补充
# 查询主键为4的书籍对应的作者的电话号码
# res = models.Book.objects.filter(pk=4).values('authors__author_detail__phone')
# print(res)
# res = models.AuthorDetail.objects.filter(author__book__pk=4).values('phone')
# print(res)
res = models.Author.objects.filter(book__pk=4).values('author_detail__phone')
print(res)
"""
11.聚合查询
聚合函数:Max Min Sum Count Avg
在ORM中支持单独使用聚合函数 aggregate
from django.db.models import Max, Min, Sum, Count, Avg
res = models.Book.objects.aggregate(Max('price' ), Count('pk' ),最小价格=Min('price' ), allPrice=Sum('price' ),平均价格=Avg('price' ))
print (res)
12.分组查询
"""
如果执行orm分组查询报错 并且有关键字sql_mode strict mode
移除sql_mode中的only_full_group_by
"""
"""
models.表名.objects.annotate() 按照表分组
models.表名.objects.values('字段名').annotate() 按照values括号内指定的字段分组
"""
res = models.Book.objects.values('publish_id' ).annotate(count_pk=Count('pk' )).values('publish_id' , 'count_pk' )
print (res)
13.F与Q查询
'''当查询条件不是明确的 也需要从数据库中获取 就需要使用F查询'''
from django.db.models import F
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title' ), Value('新款' )))
from django.db.models import Q
res = models.Book.objects.filter (~Q(pk=1 ) | Q(price__gt=2000 ))
print (res.query)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)