ORM数据增删改查 django请求生命周期 django路由层 反向解析
可视化界面之数据增删改查
补充
在模型类中定义双下str方法可以在数据对象被执行打印操作的时候方便的查看
self应该是字段对象 print(对象)时会触发__str__
并且这个方法的return一定要返回字符串类型的数据
触发提交动作的按钮:
'''
form表单中能够触发提交动作的按钮只有两个
<input type='submit'/>
<button></button>
ps: reset重置按钮
'''
1.建表
建表、加索引可以体现程序员的工作经验。
建表之前需要考虑,极端情况下 这个字段最多能存多少数据?
字段长度短了会导致服务出问题,字段长度长了会占用空间,浪费资源
在model.py使用ORM建表时,可以在类中不写主键字段(id),django会自动帮你创建一个名为id的主键字段。
可以在models.py中给字段添加注释 比如age字段 可以通过另外的方式查看字段的意义:
方式1.在mysql中使用show create table 表名
可以查看注释
方式2.mysql中有缓存表可以看
2.数据展示功能
开设接口、获取数据、传递页面、展示数据
数据展示页面示例:
数据展示页表格html:
针对数据对象主键字段的获取可以使用更加方便的 obj.pk获取
3.数据添加功能
开设接口、获取数据、发送数据、校验数据、录入数据、重定向
我们点击a标签按钮,跳转到数据添加页面,进行添加数据。
a标签相当于朝你指定的页面发送get请求:
数据添加页表单:
数据添加views层:
TODO是协同开发的时候用的 每天开发的代码要上传到网络
上传代码时,这个todo会弹出来,给你提供一些提示。
添加逻辑判断,添加成功之后,重定向到数据展示页面:
4.数据编辑功能
开设接口、后端如何区分所要编辑的数据(问号携带参数)、后端获取用户数据、前端展示默认数据、获取用户并完成更新
编辑用户信息的时候 如何让新页面知道 你想编辑的是哪个用户?
a标签默认发送get请求 我们可以使用get请求携带一些信息。
携带主键值:
示例:
数据编辑views:
使用request.GET.get
获取get请求问号后面携带的主键值。
targetEditPage: 将后端通过id值查到的数据 塞到数据添加页面表单的默认值(value)里面去!
views添加相关逻辑:
5.数据删除功能
开设接口、问号携带参数、删除二次确认
扩展1:在数据表中新建一个枚举字段,用于表示数据是否被删除,如果删除则将此字段变为false。数据展示的时候不展示false的数据。
扩展2:删除的时候可以在前端写一个模态框进行二次确认
用get请求给后端传递主键值,告知数据库到底要删除哪个数据:
在views层接收主键值,调用数据库执行删除操作:
添加模态框。给a标签添加类名,注意这里因为在循环中,所以不能添加id属性。
当模态框获取用户输入的结果是false时,使用return false取消a标签的默认事件:
django请求生命周期流程图
学习流程
路由层、视图层、模板层、模型层、组件、BBS项目
crsf
中间件:相当于安保系统 比如form表单提交 会被中间件拦住 crsf就是中间件相关配置
crsf概念理解:
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。
了解更多:https://blog.csdn.net/qq_45803593/article/details/124727762
wsgirel 与 uwsgi
django默认使用wsgiref模块写了socket服务端
没上线用wsgiref服务器 这个支持的并发量很小
项目上线之后 会使用uwsgi服务器 支持的并发量大
针对web框架网关接口有一个协议:WSGI协议
wsgiref、uwsgi都是实现WSGI协议的不同功能模块
WSGI(Python Web Server Gateway Interface, Python Web服务器网关接口)由PEP333提出,它是一种指定Web服务器与Python Web应用程序之间通信的一种标准,目的就是将Web服务器与Python Web应用解耦。
了解更多:https://www.cnblogs.com/goOJBK/p/16161273.html
nginx
对于大多数使用者来说,Nginx只是一个静态文件服务器或者http请求转发器,它可以把静态文件的请求直接返回静态文件资源,把动态文件的请求转发给后台的处理程序
了解更多:https://blog.redis.com.cn/doc/
django路由层
1.路由匹配
django2.X及以上 path第一个参数写什么就匹配什么
django1.X第一个参数是正则表达式
无论什么版本django都自带加斜杠后缀的功能 也可以取消
也就是说:django会帮你加斜杠重新给你从上到下匹配一次,一共匹配两次
示例:如下发送了两次请求
第一次请求匹配失败:
配置文件中设置APPEND_SLASH = False
可以取消这个特性但是建议不要这么做:
2.转换器功能 path
正常情况下很多网站都会有很多相似的网址 如果我们每一个都单独开设路由不合理
用django设置路由 这路由太多了不太合适
我们不可能一个接口一个接口的写啊 相似的接口要整合在一起
django2.X及以上版本路由动态匹配有转换器(五种)
str:匹配除路径分隔符外的任何非空字符串。
int:匹配0或者任意正整数。
slug:匹配任意一个由字母或数字组成的字符串。
uuid:匹配格式化后的UUID。
path:能够匹配完整的URL路径
ps:还支持自定义转换器(自己写正则表达式匹配更加细化的内容)
路由不是写死的 而是动态变化的 django提供相应的功能--> 转换器
转换器 : 将对应位置匹配到的数据转换成固定的数据类型
path('index/<str:info>/', views.index_func),
# index_func(实参request对象,info='转换器匹配到的类型转换之后的内容')
path('index/<str:info>/<int:id>/', views.index_func)
# index_func(实参request对象,info='转换器匹配到的类型转换之后的内容',id='转换器匹配到的类型转换之后的内容')
转化器的info会当做位置参数传给视图函数:
在views层接收传来的info:
3.正则匹配
django2.X及以上版本有re_path 第一个参数是正则
匹配的本质是只要第一个正则表达式能够从用户输入的路由中匹配到数据就算匹配成功会立刻停止路由层其他的匹配直接执行对应的视图函数
示例:re_path('^test/$', views.test)
举例说明:
对于如下re_path,只要目标字符串中 有test/
就能匹配成功
django1.X路由匹配使用的是url() 功能与django2.X及以上的re_path()一致。
django1.x首页的路由应该这样写:
4.正则匹配的无名有名分组
无名分组
无需给匹配条件取名字。
re_path('^test/(\d{4})/', views.test)
会将括号内正则匹配到的内容当做位置参数传递给视图函数(一个括号对应一个位置实参)
接受时候的形参无所谓,可以自己取名。
有名分组
re_path('^test/(?P<year>\d{4})/', views.test)
会将括号内正则匹配到的内容当做关键字参数传递给视图函数 year=\d{4}匹配到的内容
注意上述的分组不能混合使用!!! 不能同一个路由 既使用无名分组 又使用有名分组
反向解析
为什么要有反向解析?
当项目特别庞大 很多页面 都写了a标签进行跳转 a标签都指向同一个路由:
如果我们换路由 会将之前所有a标签全部失效!
总不能手动一个个换吧。所以要使用反向解析。
基本使用
通过一个名字可以反向解析出一个结果 该结果可以访问到某个对应的路由
1.路由匹配关系起别名
path('login/', views.login, name='login_view')
2.反向解析语法
html页面上模板语法 {% url 'login_view' %}
后端语法 reverse('login_view')
使用模板语法,当路由改变时,a标签能通过名字login_name
找到这个名字对应的路由,也动态的进行改变:
后端使用reverse反向解析:
总结:
1.起别名
2.通过这个别名不论是在前端还是在后端都能解析出来一个路由
3.这个路由就是path的第一个参数
动态路由的反向解析
path('func1/<str:others>/', views.func1_func, name='func1_view')
html页面上模板语法 {% url 'func1_view' 'jason' %}
后端语法 reverse('func1_view', args=('嘿嘿嘿',))
动态路由的情况下正常情况是无法解析的,因为构成这个路由的结果可能有,无数个。
要把动态的部分确定下来,必须得传一个具体的值(这个值可以对象点name 传数据的主键值):
如果有两个动态的参数,就传两个,用空格隔开。
后端语法:
通过args传位置参数,将动态的部分确定下来。
练习
实现一个urlpatterns的path匹配多个路由。
原匹配方式:
urlpatterns = [
path('', views.show_func),
path('user/show/', views.show_func),
path('user/add/', views.user_add_func),
path('user/edit/', views.user_edit_func),
path('user/delete/', views.user_delete_func),
]
使用分组将多个用户页面 用一个path匹配:
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.show_func),
path('user/<str:info>/', views.main_func , name='user_view')
]
在views层:
将info关键字参数传入main_func。
比如输入网页127.0.0.1/user/show/
就会执行show_func
比如输入网页127.0.0.1/user/add/
就会执行user_add_func
并且使用res接受返回值,作为main_func的返回值返回。
def main_func(request, info):
print(info)
res = func_dict.get(info)(request)
return res
func_dict = {
'show': show_func,
'add': user_add_func,
'edit': user_edit_func,
'delete': user_delete_func,
}
在前端使用反向解析:
在html页面通过user_view这个名字加上delete这个限制条件,可以解析出/user/delete/
这个网页后缀。于是相当于点击这个a标签,就向127.0.0.1/user/delete/
发送get请求,同时使用get请求的?传输主键值。
访问127.0.0.1/user/delete/
会执行user_delete_func。
在后端使用反向解析:
我们希望删除数据之后,可以重定向到展示页面。
此时可以通过reverse解析出show_page的路由/user/show/
。
reverse的第一个参数是一个名字,这个名字可以确定一个路由的动态匹配规则:
/user/<str:info>
第二个参数,相当于将原本不确定的路由给确定下来,变成:
/user/show/
最后作为一个相对路由,传入redirect。