web框架介绍
1. 什么是web框架
应该叫web应用框架(web application framework)是一种开发框架。
通俗点来说,就是用来开发web应用的程序。
2. 为什么要使用框架来开发
互联网行业流行一句话叫“不要重复造轮子”,特别是对于新手和应用层开发人员。对于web开发来说,要提高开发效率,我们需要站在前人的肩膀上,利用成熟的web框架,把精力放在业务逻辑的实现上,不关心底层建设。
本质上来讲就是一个字快。
开发一个软件项目好比盖房子:
方案一、
- 生产砖块、木头、水泥、钢筋、
- 打地基
- 盖房子
- 装修
- 购置家具
方案二、
- 找开发商买毛坯房
- 装修
- 购置家具
方案三、- 找开发商购买精装修房子
- 购置家具
很显然如果所有的工作都从头做起的方案一的效率最低,而站在前人的肩膀上的方案4是效率最高的。从方案二开始就好比是封装了底层建设的框架,不同的框架的封装程度不同,自由度和开发效率各不同。
3. 如何选择框架
如何选择框架呢?
选择web框架好比买房子选择有实力的开发商。python最流行三大框架是Django,Flask,Tornado。
- Django
- 大而全
- 入门简单
- 开发效率极高
- 最流行
- 类似于方案三(精装修的房子)
- Flask
- 轻量级
- 自由度高
- 流行
- 有一定难度
- 类似于方案二(毛坯房)
- Tornado
- 轻量级
- 自由度高
- 异步
- 难度较大
- 应用在高并发的场景
如何选择框架要根据项目的用户量,需求变动频率,开发周期等综合考虑,一般有系统架构师来决定。
4. Django是什么?
Django是一个高级的Python Web框架,它的宗旨是:Django makes it easier to build better Web apps more quickly and with less code.
发音[dʒæŋɡəʊ
]
- 开发效率极高
- 功能全面开箱即用
- 安全放心
- 社区活跃,插件丰富
因为django框架功能全面,可以看到web应用开发的全貌,学习难度也较低,推荐新手先学习。
python虚拟环境
在python项目开发过程中会下载很多第三方库,有时不同项目对同一个库的依赖版本不同,如果所有项目都使用同一个python环境就会起冲突不便于管理。
因此,实际开发中会为每一个项目都单独创建一个python的虚拟环境。这里的虚拟环境本质上是对系统python环境的一个拷贝,它依赖系统环境又和系统环境隔离。
流行的python虚拟环境管理工具有很多最常用的是virtualenv。
virtualenv
安装
首先要安装
python3.8
版本以及更高的版本
打开 cmd:
pip install virtualenv
创建虚拟环境
cd 到你想要创建虚拟环境的目录,然后运行下面的命令:
cd Desktop
virtualenv env # env
是虚拟环境的名字。如:virtualenv py3.9
运行完这个命令之后,会在当前目录下创建一个名为env的文件夹,这个文件中的内容就是环境的文件。
如果系统上有多个python环境可以通过-p参数指定不同python版本来创建对应的虚拟环境
使用虚拟环境
.\py3.9\Scripts\activate
- 显示的包:
pip list
注意
- 创建虚拟环境的目录路径中不能有中文和标点符号
- 进入虚拟环境后只在当前终端中有效,新开启的终端需要再次重新进入。如果关闭了终端会退出虚拟环境,再次进入的时候,需要重新进入虚拟环境。
退出虚拟环境
- 如果是切换,直接进入其他虚拟环境即可
- 主动退出当前虚拟环境
运行命令:deactivate
![在这里插入图片描述](https://img-blog.csdnimg.cn/60a1862ad2804921afec41341ce14460.pn
提示:
使用pycharm创建项目时会默认通过virtualenv在项目根目录下创建虚拟环境,点击terminal后会自动进入对应的虚拟环境。
创建Django项目
安装Django
进入虚拟环境中运行命令
.\py3.9\Scripts\activate
然后需要安装django,进入虚拟环境中运行命令:pip install django==3.2.17 # 指定3.2的版本
创建项目
安装django后,会安装一个django-admin程序,用来创建和管理django项目。
要创建一个django项目可以运行如下命令:
django-admin startproject mingcheng_name project_path
- 其中
startproject
是创建子命令,mingcheng_name
是项目名必须提供,project_path
是创建项目的路径,如果省略会把项目创建在当前目录下。
> 例如运行命令:
> study_django/ # 项目根目录,目录名可以随意更换
> manage.py # 管理django项目命令行工具
> study_django/ # 项目目录,python包,
> __init__.py # 起始文件
> settings.py # 项目配置文件
> urls.py # 项目根路由文件
> asgi.py # 兼容asgi协议的web服务器入口文件
> wsgi.py # 兼容wsgi协议的web服务器入口文件
但是这样项目根目录文件名和项目目录名相同,有时候我们不需要创建最外层的目录,只把项目生成在当前目录下可以运行如下命令:
django-admin startproject study_project
. # 路径参数是. 代表当前目录
运行项目
在项目根目录下运行如下命令:
- python manage.py runserver ip:端口
- 命令不带ip和端口服务将默认运行在127.0.0.1:8000
- 运行成功后在浏览器访问http://127.0.0.1:8000/将会看到欢迎页面。
注意
这只是一个Django 自带的用于开发的简易服务器,它为开发而设计,不要应用在生产环境中。
修改时区和语言
上一步中的欢迎页面看起来是英文的,
django框架
做了国际化,我们只需要在settings.py
中修改如下配置
- LANGUAGE_CODE = ‘zh-hans’
- TIME_ZONE = ‘Asia/Shanghai’
即可配置中文和正确的时区。
使用pycharm创建Django
安装:
pip install django==3.2.17
创建:django-admin startproject ck15_django .
打开:.\manage.py runserver
修改时区和语言
上一步中的欢迎页面看起来是英文的,django框架做了国际化,我们只需要在settings.py中修改如下配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
即可配置中文和正确的时区。
创建django应用
什么是应用
在Django中有项目和应用的概念。每一个应用都是一个 Python 包,并且遵循着相同的约定和结构。Django 自带一个工具,可以帮你生成应用的基础目录结构,这样你就能专心写代码,而不是创建目录了。
项目和应用有什么区别?
应用是一个专门做某件事的网络应用程序——比如博客系统,或者公共记录的数据库,或者小型的投票程序。 项目则是一个网站使用的配置和应用的集合。项目可以包含很多个应用。应用可以被很多个项目使用。
提示
也可以简单理解为一个项目即是一个网站,一个应用就是这个网站的某一个功能板块。
创建应用
在项目根目录下运行如下命令:
python manage.py startapp crm
这将会创建一个 crm 目录,它的目录结构大致如下:
crm/
__init__.py
admin.py # django后台站点配置入口
apps.py # 应用信息配置入口
migrations/ # 数据库迁移历史信息目录
__init__.py
models.py # 数据模型模块
tests.py # 单元测试
views.py # 应用视图模块
这个目录结构包括了crm应用的全部内容。
第一个视图
打开crm/views.py,编写如下代码:
from django.shortcuts import render
from django.http.response import HttpResponse
# Create your views here.
def index(request):
return HttpResponse('这是首页面')
这是 Django 中最简单的视图。如果想要看见效果,需要将一个url映射到它。
添加路由
在crm目录下创建子路由模块urls.py,编写如下代码:
from django.urls import path
from .views import index
urlpatterns = [
path('index/', index),
]
再到主路由模块study_django/urls.py中添加子路由如下:
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('crm/',include('crm.urls'))
]
做完上面的操作之后,重新运行服务,就可以通过
urlhttp://127.0.0.1:8000/crm/
访问在上面一步创建的视图。
django中的路由系统
django中路由的作用和路由器类似,当一个用户请求Django站点的一个页面时,是路由系统通过对url的路径部分进行匹配,一旦匹配成功就导入并执行对应的视图来返回响应。
django如何处理请求
- 当一个请求来到时,django首先到项目中查找根URLconf模块,在其中查找路由匹配规则。
- 根URLconf模块,就是项目文件目录下的urls.py文件。在这个文件中定义了一个变量urlpatterns。它是一个列表,其中每一个元素都是一个url模式,定义了url和视图函数的对应关系。
- django按顺序运行每个url模式,并在与请求的url匹配的第一个模式停止。
- 一旦去中一个url模式匹配,django将导入并调用该视图。
- 如果没有匹配的模式,或者在此过程中任何时候引发异常,django调用错误处理视图。
路由模块
在django中路由模块一般命名为
url.py
。
每一个路由模块中都会包含一个urlpatterns
变量,它是一个django.urls.path()
或者django.urls.re_path()
实例的列表。
根路由模块
最外层的路由模块,路由解析的入口。
django通过设置ROOT_URLCONF
来确定主路由模块,通常是项目目录下的urls.py
模块。
子路由
主路由包含的其他路由都是子路由。
一般都是各自应用目录下的urls.py
模块。
path()
path(route,view, kwargs=None,name=None)
path
函数返回一个对象,表示一个路由规则route
:一个字符串,表示url规则view
: 一个视图kwargs
:一个字典,需要传入的额外参数name
:url的命名
案例:
上一节,我们在crm应用中定义了如下路由:
path('index/', views.index)
将'index/'
和视图views.index
进行映射。
include()
- include(module, namespace=None)
- 将一个子路由导入到一个URLconf模块中
- module: URLconf模块(或模块名称)
案例:
上一节,我们在根路由中,通过include
包含了crm
子路由:
path('crm/', include('crm.urls'))
将crm/
和子路由crm.urls
进行映射。
URLconf在什么上查找
- 请求的url会被看做是一个普通的
Python
字符串,URLcon
f在其上查找并匹配。- 进行匹配时不包含
GET
或POST
请求方式的参数以及域名。- 例如,
https://www.example.com/myapp/
请求中,URLconf
将查找myapp/
- 在
https://www.example.com/myapp/?page=3
请求中,URLconf
仍将查找myapp/
。- URLconf不检查使用哪种请求方法。
- 换句话说,所有请求方法,对同一个
URL
无论是POST
请求,GET
请求等等,都将路由到相同的视图函数。
案例:
所以在浏览器中访问地址http://127.0.0.1/crm/index/
时,URLconf
将查找crm/index/
。
第一步在跟路由中进行匹配,可以匹配到:
- path(‘crm/’, include(‘crm.urls’))
第二步当遇到
include()
时,它会将匹配到该点的URL部分cmr/
切掉,并将剩余字符串index/
发送到包含的crm.urls
模块中进一步匹配
第三/index在crm.urls路由中可以匹配到:
- path(‘index/’, views.index)
没有下一步匹配,直接执行对应的视图函数
views.index
。
注意,这个过程会递归的进行,中间遇到任何一条匹配的路由就会返回。
在URL中捕获参数
django允许在url中捕获值,若要从URL中捕获值,请使用尖括号。
尖括号定义变量名,捕获的值传递给视图函数相同名称的参数。格式如下:
- ‘<参数名>’
案例:
写一个学生详情接口,通过crm/students/n/
返回id为n的学生的信息。
视图代码:
# crm/views.py
def detail(request, pk):
return HttpResponse('学生id为{}的详情'.format(pk)) # 模拟返回对应学生的详情
路由代码:
from django.urls import path, re_path
# 这是一个约定的变量名,不能改
from . import views
urlpatterns = [
path('index/', views.index),
path('students/<int:pk>', views.students_002),
]
现在,在浏览器中访问:
http://127.0.0.1:8000/crm/students/2/
会返回页面:
注意看路由部分的
<pk>
,这里的pk对应视图函数的pk
形参。django
会自动匹配url
中这部分的字符串2
然后传递给detail
函数的pk
形参。
路径转换器
上面的案例有个漏洞,如果我们在浏览器中输入
http://127.0.0.1:8000/crm/students/aaa/
,我们发现它依然可以访问。
在实际开发中,这显然不对,
id
不可能是个字符串。当然可以在view
中进行类型转换,但是不够通用。django
中设计了路径转换器,能够在路由匹配时,自动进行转换。
以下路径转换器在默认情况下是可用的:
str
: 匹配除了路径分隔符/之外的任何非空字符串。如果表达式中不包含转换器,默认为字符串转换器。
int
: 匹配0或任何整数。返回一个整数类型
slug
: 匹配任何由ASCII
字符或数字组成的slug
字符串,加上连字符和下划线。
uuid
: 匹配格式化的UUID
。为了防止多个url映射到同一个页面,必须包含破折号并且必须是小写字母。例如:075194d3-6885-417e-a8a8-6c931e272f00
path
: 匹配任何非空字符串,包括路径分隔符/。这允许匹配完整的URL路径,而不是像str那样仅匹配url路径部分。
路径转换器的使用方式非常简单,只需要在捕获符号
<>
中,以以下语法即可:
我们可以将上面的案例修改为:
path('students/<int:pk>/', views.detail)
然后,我们再次访问`http://127.0.0.1:8000/crm/students/aaa/,结果是404。
当然,我们也可以捕获多个值,看如下案例:
视图代码:
# crm/views.py
def student_003(request, month, year):
return HttpResponse(f'{year}年{month}月报名的学生的列表')
路由代码:
# crm/urls.py
urlpatterns = [
...
path('students/<int:year>-<int:month>/', views.student_003),
]
那么通过url
http://127.0.0.1:8000/crm/students/2022/01
和http://127.0.0.1:8000/crm/students/2022-01/
会得到相同的结果。
但是如果访问http://127.0.0.1:8000/crm/students/9527-100/也会得到结果:
这显然又是bug。
路径转换器只能进行简单的类型转换和匹配,还需要更强大的匹配功能,需要用到re_path()
函数。
re_path()
re_path(route,view, kwargs=None,name=None)
函数返回一个对象,表示一条路由规则。route
: 一个字符串,表示一个url规则view
:一个视图kwargs
: 一个字典,需要传入的额外参数name
: url命名
与
path()
不同的是,route
部分包含正则表达式。
当进行匹配时,从正则表达式中捕获的组会被传递到视图中。
如果组是命名的,则作为命名参数,否则作为位置参数。值以字符串的形式专递,不进行任何类型转换。
命名正则表达式分组的语法是:(?P<name>pattern)
,其中name
是组的名称,pattern
是要匹配的某个模式。
下面是前面例子中的路由,使用正则表达式重写:
urlpatterns = [
re_path(r'students/(?P<year>\d{4})/(?P<month>0[1-9]|[1-9]|1[0-2])/', views.student_003),
]
这样写和之前的路由匹配一致,只是:
- 匹配的url会受到限制,例如:
100月将不再匹配,因为月份整数被限制为1-12。
- 捕获的每个参数都以字符串的形式发送到视图。
- 当从使用
path()
切换到re_path()
或相反时,特别重要的是注意视图参数的类型会发生变化,因此可能需要调整视图。
使用没有命名分组的正则表达式
除了命名组语法,例如
(?P<year>\d{4})
,还可以使用较短的未命名组,例如(\d{4})
。这种写法并不特别推荐,因为它更容易在匹配的预期含义和视图参数之间意外的一如错误。
注意在实际使用中建议只使用一种,要么命名,要么不命名,因为当两种方式混合使用时,会忽略未命名的组,只将命名的组传递给视图函数。