django之路由层和反向解析及正则
可视化界面之数据增删改查
针对数据对象主键字段的获取可以使用更加方便的obj.pk获取
在模型类中定义双下__str__方法可以在数据对象被执行打印操作的时候方便查看
"""
form表单中能够触发提交动作的按钮只有两个
<input type='submit'>
<button></button>
"""
1.数据展示功能
开设接口、获取数据、传递页面、展示数据
2.数据添加功能
开设接口、获取数据、发送数据、校验数据、录入数据、重定向
3.数据编辑功能
开设接口、后端如何区分要编辑的数据(问号携带数据)、后端获取用户数据、前端展示默认数据、获取用户并完成更新
4.数据删除功能
开设接口、问号携带参数、删除二次确认
项目初始化步骤
1.创建django项目,创建模板和静态目录,创建app
django-admin startproject djangoday03
cd djangoday03
mkdir templates
mkdir static
python38 manage.py startapp app01
2.pycharm打开新创建的djangoday03项目
3.修改templates路径(settings.py)
'DIRS': [os.path.join(BASE_DIR,'templates')],
4.注册app01(settings.py)
INSTALLED_APPS = [
'app01',
]
5.修改数据库为mysql(settings.py)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'day51',
'HOST':'127.0.0.1',
'PORT':3306,
'USER':'root',
'PASSWORD':'Abcd1234',
'CHARSET':'utf8',
}
}
6.添加静态路径支持(settings.py)
STATICFILES_DIRS = [os.path.join(BASE_DIR,'static'),
]
7.post发送请求会报错注释其中的一行(settings.py)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
8.ORM数据模型准备(app01里面的models.py)
class User2(models.Model):
# 主键字段可以不写 ORM会自动帮你创建一个id的主键字段
name = models.CharField(max_length=32,verbose_name='用户名')
age = models.IntegerField(verbose_name='年龄')
# 便于对象打印之后的查看 不影响数据库 所以不需要执行迁移命令
def __str__(self):
return '用户对象:%s' % self.name
9.启动django服务
python38 manage.py runserver
10.执行数据库迁移相关命令(操作前确保没有相关表)
python38 manage.py makemigrations 将操作记录到小本本上(migrations)
python38 manage.py migrate 将操作同步到数据库上
11.对User2表填充相关数据
#登录数据库客户端day51库下进行操作,模拟数据
insert into app01_user2(name,age) values('jason',18),('tony',19),('winter',23),('jerry',28),('oscar',32);
访问用户数据的接口
1.添加路由及对应的功能函数(urls.py)
from app01 import views
# 访问用户数据的接口
path('user_list/',views.user_list_func),
2.编辑视图层,添加后端功能(view.py)
from django.shortcuts import render,HttpResponse,redirect
from app01 import models
# Create your views here.
def user_list_func(request):
# 1.获取user2表中所有的数据展示到html页面上
user_data = models.User2.objects.filter() # 括号内不填筛选条件等价于查看所有 QuerSet [对象1,对象2,对象3...]
# 2.利用模板语法传递数据到html页面并完成处理最终返回给浏览器展示
return render(request,'userListPage.html',{'user_data':user_data})
3.准备对应的userListPage.html文件
1.拷贝bootstrap-3.4.1-dist本地静态资源到static目录下
2.编写userListPage.html文件(templates目录)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1 class="text-center">数据展示页</h1>
<div class="col-md-8 col-md-offset-2">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Age</th>
<th class="text-center">Operation</th>
</tr>
</thead>
<tbody>
{% for user_obj in user_data %}
<tr>
<td>{{ user_obj.pk }}</td>
<td>{{ user_obj.name }}</td>
<td>{{ user_obj.age }}</td>
<td class="text-center">
<a href="#" class="btn btn-primary btn-xs">编辑</a>
<a href="#" class="btn btn-danger btn-xs delete">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
4.浏览器打开访问
http://127.0.0.1:8000/user_list/
数据添加
1.添加路由层(urls.py)
# 添加用户数据的接口
path('user_add/',views.user_add_func),
2.编辑视图层,添加后端功能(view.py)
def user_add_func(request):
#1.先返回一个获取新增用户数据的html页面
return render(request,'userAddPage.html')
3.创建对应userAddPage.html文件(templates目录)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1 class="text-center">数据添加页</h1>
<div class="col-md-6 col-md-offset-3">
<form action="" method="post">
<p>name:
<input type="text" name="name" class="form-control">
</p>
<p>age:
<input type="text" name="age" class="form-control">
</p>
<input type="submit" value="添加用户" class="btn btn-warning btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
4.数据展示页面要添加一个数据添加入口(userListPage.html)
<h1 class="text-center">数据展示页</h1>
<div class="col-md-8 col-md-offset-2">
<a href="/user_add/" class="btn btn-success">数据添加</a> /添加这行/
5.再次编辑后端逻辑接口(views.py)
def user_add_func(request):
#2.根据不同的请求方式做不同的处理
if request.method == 'POST':
#3.获取用户相关数据
name_data = request.POST.get('name')
age_data = request.POST.get('age')
#4.继续一些小的判断
if len(name_data) == 0 or len(age_data) ==0:
return HttpResponse('用户名或年龄不能为空')
user_data=models.User2.objects.filter(name=name_data)
if user_data:
return HttpResponse('用户名已存在')
models.User2.objects.create(name=name_data,age=age_data)
# 5.重定向到数据展示页
return redirect('/user_list/')
#1.先返回一个获取新增用户数据的html页面
return render(request,'userAddPage.html')
数据编辑
1.添加路由层(urls.py)
# 编辑用户数据的接口
path('user_edit/',views.user_edit_func),
2.编辑视图层,添加后端功能(view.py)
ps:在编辑之前需要修改原来userListPage.html编辑按钮的功能,收集用户点击编辑特定数据,传输给后端用来判断要编辑具体哪一条数据
<a href="/user_edit/?edit_id={{ user_obj.pk }}" class="btn btn-primary btn-xs">编辑</a>
#当用户点击编辑按钮的时候,默认向后端传送?edit_id=用户主键ID,方便后端收集到对应数据进行对应操作
def user_edit_func(request):
#1.获取用户想要编辑的数据主键值
target_edit_id = request.GET.get('edit_id')
#4. 根据不同的请求处理不同的逻辑
if request.method == 'POST':
name_data = request.POST.get('name')
age_data = request.POST.get('age')
if len(name_data)==0 or len(age_data)==0:
return HttpResponse('用户名或年龄不能为空')
models.User2.objects.filter(pk=target_edit_id).update(name=name_data,age=age_data)
# 5.重定向到数据展示页
return redirect('/user_list/')
#2.根据主键值获取对应的数据
target_edit_obj = models.User2.objects.filter(pk=target_edit_id)[0] # QuerySet[对象1,对象2...]
#3.返回一个编辑数据的页面,并且该页面上需要提前展示出原来的数据
return render(request,'userEditPage.html',{'target_edit_obj':target_edit_obj})
3.创建对应userEditPage.html文件(templates目录)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1 class="text-center">数据编辑页</h1>
<div class="col-md-6 col-md-offset-3">
<form action="" method="post">
<p>name:
<input type="text" name="name" class="form-control" value="{{ target_edit_obj.name }}">
</p>
<p>age:
<input type="text" name="age" class="form-control" value="{{ target_edit_obj.age }}">
</p>
<input type="submit" value="编辑用户" class="btn btn-primary btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
4.访问如下:
数据删除
1.添加路由层(urls.py)
# 删除用户数据的接口
path('user_delete/',views.user_delete_func),
2.编辑视图层,添加后端功能(view.py)
ps:在编辑之前需要修改原来userListPage.html删除按钮的功能,收集用户点击删除特定数据,传输给后端用来判断要编辑具体哪一条数据
<a href="/user_delete/?delete_id={{ user_obj.pk }}" class="btn btn-danger btn-xs delete">删除</a>
#当用户点击删除按钮的时候,默认向后端传送?delete_id=用户主键ID,方便后端收集到对应数据进行对应操作
def user_delete_func(request):
target_delete_id = request.GET.get('delete_id')
models.User2.objects.filter(pk=target_delete_id).delete()
return redirect('/user_list/')
3.编辑userListPage.html,增加删除确认功能
<a href="/user_delete/?delete_id={{ user_obj.pk }}" class="btn btn-danger btn-xs delBtn">删除</a>
<script>
$('.delBtn').click(function (){
let res = confirm('你确定要删除吗?')
if (res){
}else{
return false
}
})
</script>
</body>
4.验证删除功能
django请求生命周期流程图
学习流程:路由层、视图层、模板层、模型层、组件、BBS项目
1.web服务网关接口
web服务网关接口协议-WSGI协议,wsgiref和uwsgi都是该协议的两种不同功能模块
wsgiref:django的默认网关接口,能承受的并发量特别低,只用于本地,实际项目中会切换成uwsgi。uwsgi上线后会切换成uwsgi,并发量比wsgiref高很多。
django路由层
路由匹配
django2.x及以上path第一个参数写什么就匹配什么
django1.x第一个参数是正则表达式
无论什么版本django都自带加/后缀并重定向的功能,可以取消,在settings.py中,APPEND_SLASH = False
转换器(动态匹配)
正常情况下很多网站都会有很多相似的网址 如果我们每一个都单独开设路由不合理,django2.x及以上版本路由动态匹配有转换器(五种)
str: 匹配除路径分隔符外的任何非空字符串(常用)
int:匹配0或者任意正整数(一般)
slug:匹配任意一个由字母或数字组成的字符串
uuid:匹配格式化后的UUID
path:能够匹配完整的URL路径
ps:还支持自定义转换器(自己写正则表达式匹配更加细化的内容)
将对应位置匹配到的数据转换成固定的数据类型
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=‘转换器匹配到的类型转换之后的内容’)
验证:
urls.py:
path('index/<str:info>/',views.index_func),
views.py
def index_func(request,info):
print('info:',info)
return HttpResponse("index func")
浏览器输入:http://127.0.0.1:8000/index/hello/
返回index func
打印info:hello
urls.py:
path('index/<str:info>/<int:id>',views.index_func),
views.py
def index_func(request,info,id):
print('info:',info)
print('id:',id)
return HttpResponse("index func")
浏览器输入:http://127.0.0.1:8000/index/hello/123412
返回index func
打印info:hello
id: 123412
正则匹配
django2.x及以上版本有re_path 第一个参数是正则
匹配的本质是只要第一个正则表达式能够从用户输入的路由中匹配到数据就算匹配成功会立刻停止路由层其它的匹配直接执行对应的视图函数
re_path('^test/$',views.test)
django1.x路由匹配使用的是url()功能与django2.x及以上的re_path()一致
正则匹配的无名分组
re_path('^test/(\d{4})/',views.test)
会将括号内正则匹配到的内容当做位置参数传递给视图函数
验证:
urls.py:
from django.urls import path,re_path #导入re_path模块
re_path('^test/(\d{4})/(.*?)/',views.test),
views.py
def test(request,aaa, others):
print('aaa',aaa)
print('others',others)
return HttpResponse("test")
浏览器输入:http://127.0.0.1:8000/test/1234/sdaf/
页面返回:test
pycharm打印:
aaa 1234
others sdaf
正则匹配的有名分组
re_path('^test/(?P<year>\d{4})/',views.test) test(实参request对象,year='\d{4}匹配到的内容',others='.*?匹配到的内容')
会将括号内正则匹配到的内容当做关键字参数传递给视图函数
注意:有名和无名不能混合使用!!!
反向解析(重要)
通过一个名字可以反向解析出一个结果 该结果可以访问到某个对应的路由
基本使用
1.路由匹配关系起别名
path('login/',views.login,name='login_view')
2.反向解析语法
html页面上模板语法{%url 'login_view'%}
后端语法 reverse('login_view')
验证
urls.py
path('login111/',views.login,name='login_view'),
path('home/',views.home),
views.py
from django.shortcuts import render,HttpResponse,redirect,reverse #导入模块
def login(request):
return HttpResponse('login html')
def home(request):
print(reverse('login_view'))
return render(request,'homePage.html')
HomePage.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>home页面</h1>
<a href="{% url 'login_view' %}">111</a>
<a href="{% url 'login_view' %}">222</a>
<a href="{% url 'login_view' %}">333</a>
</body>
</html>
浏览器输入:http://127.0.0.1:8000/home/
变更urls.py
path('login222/',views.login,name='login_view'),
再次刷新浏览器查看:http://127.0.0.1:8000/home/
动态路由的反向解析
path('func1/<str:others>/', views.func1_func, name='func1_view')
html页面上模板语法 {% url 'func1_view' 'jason' %}
后端语法 reverse('func1_view', args=('嘿嘿嘿',))
验证
urls.py:
path('func1/<str:others>/',views.func1_func,name='func1_view')
views.py
def home(request):
print(reverse('login_view'))
print(reverse('func1_view', args=('嘿嘿嘿',)))
return render(request, 'homePage.html')
def func1_func(request, others):
return HttpResponse('func1_func html')
HomePage.html
<a href="{% url 'func1_view' 'jason' %}">555</a>
<a href="{% url 'func1_view' 'tony' %}">555</a>
<a href="{% url 'func1_view' 'jerry' %}">555</a>
</body>
浏览器输入:http://127.0.0.1:8000/home/
变更urls.py
path('func11/<str:others>/',views.func1_func,name='func1_view')
locals
locals() 函数会以字典类型返回当前位置的全部局部变量。
一般在html页面中用到,案例:
return render(request,'bookAddPage.html',locals())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗