目录
一、Web框架
二、WSGI协议
三、 Django框架
1、MVC与MTV模型
2、Django的下载与使用
补充
3、启动django项目
补充
5、 Django请求生命周期
四、路由控制
1、路由是什么?
2、如何使用
3、path详细使用
4、re_path详细使用
5、反向解析
6、路由分发
五、视图层
1、格式
2、响应对象(本质上都是HttpResponse)
3、 CBV和FBV
4、关于类中self是谁的问题
5、上传文件
Web框架(Web framework)是一种开发框架,用来支持动态网站、网络应用和网络服务的开发。这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方法。web框架已经实现了很多功能,开发人员使用框架提供的方法并且完成自己的业务逻辑,就能快速开发web应用了。浏览器和服务器的是基于HTTP协议进行通信的。也可以说web框架就是在以上十几行代码基础张扩展出来的,有很多简单方便使用的方法,大大提高了开发的效率。
即别人帮咱们写了一些基础代码 -------》我们只需要在固定的位置写固定的代码 ------》就能实现一个web应用
最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。
如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。
正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI。
基于这个协议的web服务器
协议到底怎么规定的:
使用wsgiref写个web服务
from wsgiref.simple_server import make_server
def mya(environ, start_response):
print(environ)
start_response('200 OK', [('Content-Type', 'text/html')])
if environ.get('PATH_INFO') == '/index':
with open('index.html','rb') as f:
data=f.read()
elif environ.get('PATH_INFO') == '/login':
with open('login.html', 'rb') as f:
data = f.read()
else:
data=b'Hello, web!
'
return [data]
# 可调用对象---》能加括号执行的对象
if __name__ == '__main__':
myserver = make_server('', 8011, mya)
# 请求来了---》经过wsgiref---》调用后面的可调用对象
# ---》传入两个参数(environ, start_response)
print('监听8011')
myserver.serve_forever()
所有Web框架其实都遵循MVC架构
1.1 MVC:把本来坨在一起的代码拆到不同的位置
MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求。
1.2 MTV
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:
在命令行输入:
pip uninstall django # 卸载
pip3 install django # 如果不指定就会装最新版本
创建项目:
目录结构:
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等。
环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。
python manage.py runserver 8001
这样我们的django就启动起来了!当我们访问:http://127.0.0.1:8080/时就可以看到:
0.0.0.0和localhost和127.0.0.1有什么区别?
1、0.0.0.0
严格说来,0.0.0.0已经不是一个真正意义上的IP地址了。
它表示的是一个集合:所有 不清楚 的主机和目的网络。
“不清楚”:在本机的路由表里没有特定条目指明如何到达。对本机来说,它就是一个“收容所”,所有不认识的“三无”人员,一律送进去。如果在网络设置中设置了缺省网关,那Windows系统会自动产生一个目的地址为0.0.0.0的缺省路由。
用途:
2、127.0.0.1(一种本机保留的私有 IP)
本机地址,主要用于测试,即“我自己”。寻址这样一个地址,是不能把它发到网络接口的。除非出错,否则在传输介质上永远不应该出现目的地址为“127.0.0.1”的数据包。
127.0.0.1属于{127,}集合中的一个,而所有网络号为127的地址都被称之为环回地址,环回地址!== 127.0.0.1,它们是包含关系,即环回地址包含 127.0.0.1。
环回地址:所有发往该类地址的数据包都应该被loop back。所有发往目标IP为127.0.0.1的数据包都不会通过网卡发送到网络上,而是在数据离开网络层时将其回送给本机的有关进程。
用途:
3、localhost
相比127.0.0.1,localhost具有更多的意义。localhost是个域名,而不是一个ip地址。可修改。
用于指代 this computer 或者 this host,可以用它来获取运行在本机上的网络服务。
在大多数系统中,localhost被指向了 IPV4 的 127.0.0.1 和 IPV6 的 ::1,这就是把localhost与127.0.0.1等同的原因。
总结:
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。即请求路径和要执行的视图函数的对应关系。
path('admin/', login)
等价于:_path(route, view, kwargs=None, name=None)
第一个参数:准确路径,字符串
转换器: '
127.0.0.1:8080/login/justin ----> path('login/', admin.site.urls),
def login(request,name)
第二个参数: 视图函数的内存地址,不要加括号
第三个参数:kwargs是给视图函数传递默认参数
第四个参数:路径的别名 -----》后期使用反向解析得到该路径
在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
没有转换器的情况:
path('login/', login,name='login')
res = reverse('login') # 当时定义路径传入的name参数对应的字符串
有转换器的情况:
path('login/', login,name='login')
res = reverse('login',kwargs={name:lqz}) # 当时定义路径传入的name参数对应的字符串
生成这种路径:'login/lqz'1
#主urls
from django.urls import path,re_path,include
from app01 import views
from app01 import urls
urlpatterns = [
# re_path(r'^app01/',include('app01.urls')),#行
# re_path(r'^app01/&',include('app01.urls')),#不行
# path('app01/',include('app01.urls')),#行
#path('app01/', include(urls)),
]
在app01里创建一个urls
from django.urls import path,re_path
from app01 import views
urlpatterns = [
re_path(r'^test/(?P[0-9]{2})/$',views.url_test),
]
views.py ----》这个文件目前写的是视图函数
def 视图函数(request):
return 四件套
JsonResponse源码分析
return JsonResponse({name:kevin,age:19})
# 触发 JsonResponse的__init__--->{name:kevin,age:19}给了data
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,json_dumps_params=None, **kwargs):
# 如果传入的是字典
# safe是True,后面是False,条件不符合,内部就不会走
if safe and not isinstance(data, dict):
# isinstance(对象, 类) 判断这个对象,是不是这个类的对象
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None: # 条件符合
json_dumps_params = {}
# kwargs是字典---》setdefault--》有则修改,无则新增
kwargs.setdefault('content_type', 'application/json')
# 核心---》把字典转成json格式字符串,赋值给data
data = json.dumps(data, cls=encoder, **json_dumps_params)
# super().__init__ 调用父类的 __init__ 完成实例化---》HttpResponse的对象
return HttpResponse(data,**kwargs)
super().__init__(content=data, **kwargs)
FBV(Function base view):基于函数的视图
CBV(Class base view):基于类的视图
CBV经典写法:
from django.views import View
class UserView(View):
# 写方法---》跟请求方式同名的方法
def get(self,request,*args,**kwargs)
# 必须返回四件套
# 路由配置
path('index/', 视图类名.as_view()) # as_view是类的绑定方法
执行流程 ----》源码分析
path('index/', index), --->请求来了,路由匹配成功会执行 index(request,)
path('index/', UserView.as_view()),
# 入口:路由 ---》as_view来开始
# 请求来了,路由匹配成功---》执行---》UserView.as_view()(request)
# 需要看as_view()执行结果是什么--》view--》代码如下:
def view(request, *args, **kwargs): # 方法,可以加括号调用
return self.dispatch(request, *args, **kwargs)
# 本质就是在执行 view(request)
# 本质在执行---》self.dispatch(request, *args, **kwargs)
# 去类(UserViwe类中找,找不到,去父类View)中找dispatch,代码如下:
def dispatch(self, request, *args, **kwargs):
"""request当次请求的请求对象,取出请求方式【假设是get请求】,转成小写 'get'
http_method_names = ['get', 'post', 'put']
条件成立,执行if内部代码"""
if request.method.lower() in self.http_method_names:
"""getattr:反射 ---》通过字符串去对象中取属性或方法
self是谁的对象? 是View这个类的对象,这个是视图类UserView的对象
取出来的handler是UserView这个类的get方法"""
handler = getattr(self, 'get')
else:
handler = self.http_method_not_allowed
# handler是 UserView这个类的get方法
"""get(request)---》触发UserView这个类的get方法
---》真正执行原来视图函数的内容"""
# 最终返回
return handler(request, *args, **kwargs)
总结:
class Animal:
def run(self):
# 这个self,是谁调用,就是谁
print(type(self))
#
#
print(self.name, '走路')
class Person(Animal):
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, age):
self.name = name
self.age = age
p = Person('kevin')
p.run() # kevin 走路
dog = Dog('小奶狗', 6)
dog.run() # 小奶狗 走路
总结:
self是谁调用。self就是谁,不能只看是哪个类
以后看到self.方法的时候,不要只从当前类,或父类中找,应该先确定当前self是谁,然后从这个对象的类根上开始找。
TEMPLATES --->'DIRS': [os.path.join(BASE_DIR, 'templates')]
class FileView(View):
def get(self,request):
return render(request,'file.html')
def post(self,request):
# 拿出文件对象
my_file=request.FILES.get('myfile')
print(type(my_file))
# django.core.files.uploadedfile.InMemoryUploadedFile
# 跟之前用的文件对象不一样,但是它应该继承了文件
from django.core.files.uploadedfile import InMemoryUploadedFile
# 1 保存 2 取出文件名字
# my_file.save() # 找了一顿,没有,所以不能使用快捷保存方式,需要自己写保存
print(my_file.name) # 3-回顾django.md
# 自己写保存,放在项目根路径下
with open(my_file.name,'wb') as f:
for line in my_file:
f.write(line)
return HttpResponse('上传成功')
Title