目录:
- Web框架本质----socket
- MVC和MTV架构
- Django常用命令
- 配置settings.py文件
- Django各种url写法
- Django的CBV和FBV
- 前后端交互:提交数据、提交文件
- Django生命周期与中间件
一. Web框架本质----socket
1、web框架本质
1. 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
2. 真实web框架一般会分为两部分:服务器程序和应用程序。
1)服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理
2)应用程序则负责具体的逻辑处理
2、WSGI(Web Server Gateway Interface)
1. 不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。
2. 这样,服务器程序就需要为不同的框架提供不同的支持,只有支持它的服务器才能被开发出的应用使用,这时就需要有一个标准
3. WSGI是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。
3、使用socket创建一个简单web服务
使用socket创建一个简单web服务
4、自定义Web框架
说明: 通过python标准库提供的wsgiref模块开发一个自己的Web框架
自定义web框架
二. MVC和MTV架构
1、MVC架构
- MVC架构把一个完整的程序或者网站项目分成三个主要的组成部分,分别是Model模型,View视图,Controller控制器
- 希望一个项目可以让内部数据的储存方式,外部的可见部分以及过程控制逻辑相互配合运行
- 进一步简化项目复杂度,提高可扩充性,维护性,有助于不同成员之间的分工
2、MTV框架(Django)
- 对于网站而言,网页服务器在接收到远程浏览器的请求的时候,不同的网址做出不同的响应
- 有不同的链接方式其实就隐含了逻辑控制,因此很难严谨的将其定义为上述三个部分
- 因此Django另外设计了MTV结构(Model,Template,View)。
3、MVC vs MTV
MVC:
- MVC Model(数据库 ) View(模板文件) Controller(业务处理)
- M( Model): 主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作。
- V( View): 用于封装结果,生成页面展示的html内容。
- C(Controller): 用于接收请求,处理业务逻辑,与Model和View交互,返回结果。
MTV:
- MTV Model(数据库) Template(模板文件) View( 业务处理)
- M( Model): 与MVC中的M功能相同,负责和数据库交互,进行数据处理。
- V( View): 与MVC中的C功能相同,接收请求,进行业务处理,返回应答。
- T(Template): 与MVC中的V功能相同,负责封装构造要返回的html。
三. Django常用命令
1、安装Django
- pip3 install django
2、创建Django工程
D:\> django-admin startproject laoniu //创建项目名称laoniu
D:\> cd laoniu
D:\laoniu> python manage.py runserver 127.0.0.1:8002 //运行laoniu即可用浏览器访问了
D:\laoniu> python manage.py createsuperuser //创建Django admin用户
3、创建app
- python manage.py startapp app01 //创建子应用
4、迁移表&创建超级用户
迁移命令:
- python manage.py makemigrations
- python manage.py migrate
创建超级用户命令:
- python manage.py createsuperuser
3.安装应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#添加子应用
'book.apps.BookConfig'
]
5.本地化
#设置中文
LANGUAGE_CODE = 'zh-Hans'
#亚洲上海时区
TIME_ZONE = 'Asia/Shanghai'
6.模板路径
- 在应用同级目录下,创建templates 模板文件夹,
然后创建路径:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
7.项目中匹配urls
正则 : 路径只要不是admin/就算匹配成功。并包含到应用中的urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
#正则为:只要不是 admin/ 就算匹配成功
url(r'^',include('book.urls'))
]
8.应用中匹配 urls.py
正则 : 路径中包含 booklist/,就调用视图中对应的 bookList 函数
from django.conf.urls import url
from book.views import bookList
urlpatterns = [
# 匹配书籍列表信息的URL,调用对应的bookList视图
url(r'^booklist/$',bookList)
]
9.准备视图
# 定义视图:提供书籍列表信息
def bookList(request):
return HttpResponse('OK!')
10.开启服务器, 测试项目
# 进入项目文件中, 开启项目对应的服务器
python manage.py runserver
# 浏览器中输入网址
http://127.0.0.1:8000/booklist/
配置:
在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
1.使用MySQL数据库首先需要安装驱动程序
2.在Django的工程同名子目录的__init__.py文件中添加如下语句
import pymysql
pymysql.install_as_MySQLdb()
- 作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。
3.修改DATABASES配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'mysql', # 数据库用户密码
'NAME': 'book' # 数据库名字
}
}
4.在MySQL中创建数据库
create database book charset=utf8;
11、执行python manage.py migrate无法创建表
-
执行时报:No migrations to apply.
- 进入数据库,找到django_migrations的表,删除该app名字对应的所有记录
- python manage.py dbshell
- delete from django_migrations where app=‘app01’;
-
删除该app名字下的migrations下的除了__init__.py之外的文件。
-
执行下面这两条命令:(在项目目录下)
- python manage.py makemigrations
- python manage.py migrate
注:如果个别app表依然无法建立可以在后面添加app名称:python manage.py makemigrations/migrate app01
12、“Column ‘last_login’ cannot be null”报错
mysql> SELECT * FROM django_migrations;
mysql> TRUNCATE TABLE django_migrations;
$ python manage.py migrate --fake-initial
Make sure this message appears: 0005_alter_user_last_login_null - [OK]
13、windows中杀死指定端口号进程
- D:>netstat -aon|findstr “8000”
- D:>taskkill /PID 12516 -t -f
四. 配置settings.py文件
1、配置模板的路径
TEMPLATES = [
{
'DIRS': [os.path.join(BASE_DIR,'templates')],
},
]
2、 配置静态目录
#像ccs和js这些静态文件如果想要使用必须在这里配置路径
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
3、注释CSRF
MIDDLEWARE = [
# 'django.middleware.csrf.CsrfViewMiddleware',
]
4、修改settings.py中时区
修改settings.py中时区:
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
五. Django各种url写法
1、无正则匹配url (http://127.0.0.1:8000/index/?nid=1&pid=2)
urls.py:
urlpatterns = [
url(r'^index/', views.index),
]
views.py:
from django.shortcuts import render
def index(request):
print(request.GET.get('nid')) # 1
print(request.GET.get('pid')) # 2
return render(request,'index.html')
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/index/?nid=1&pid=2"> url.py中不必用正则匹配 </a>
</body>
</html>
2、使用name构建自己想要的url
1. 使用name在前端和后端分别构建自己想要的url
urls.py中定义路由系统:
urlpatterns = [
url(r'^index1/', views.index,name='indexname1'),
url(r'^index2/(\d+)/(\d+)/', views.index,name='indexname2'),
url(r'^index2/(?P<pid>\d+)/(?P<nid>\d+)/', views.index,name='indexname3'),
]
views.py中根据reverse模块构建url路径:
from django.shortcuts import render
from django.core.urlresolvers import reverse
def index(request,*args,**kwargs):
url1 = reverse('indexname1') # /index1/
url2 = reverse('indexname2', args=(1,2,)) # /index2/1/2/
url3 = reverse('indexname3', kwargs={'pid': 11, "nid":22}) # /index2/11/22/
return render(request,'index.html')
index.html中构建url路径:前端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p><a href="{% url 'indexname1' %}"> http://127.0.0.1:8000/index/ </a></p>
<p><a href="{% url 'indexname2' 1 2 %}"> http://127.0.0.1:8000/index2/1/2/ </a></p>
<p><a href="{% url 'indexname3' 11 22 %}"> http://127.0.0.1:8000/index2/11/22/ </a></p>
</body>
</html>
2. 根据request.path中的绝对路径反解出url中的name名字
resolve_url_obj = resolve(request.path) #request.path路径: /student/homework_detail/52
resolve_url_obj.url_name #从path中解析出url名字 url_name = homework_detail
3、Django路由分发 并使用name构建url路径
**作用:对URL路由关系进行命名, 以后可以根据此名称生成自己想要的URL **
/project/urls.py:
from django.conf.urls import url,include
from app01 import urls
urlpatterns = [
url(r'^app01/', include("app01.urls", app_name='app01', namespace='app01')),
]
/app01/urls.py:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^index/$', views.index, name='index'),
]
views.py:
from django.shortcuts import render
def index(request):
return render(request,'index.html')
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p> <a href="{% url "app01:index" %}"> http://127.0.0.1:8000/app01/index/</a></p>
</body>
</html>
六. Django的CBV和FBV
1、FBV(function base view):在views.py文件中使用函数
FBV写法:
def index(request):
return render(request, 'index.html')
2、CBV(class base view):在views.py文件中使用类
- dispatch是父类中用来反射的函数,找对应的函数(比对应函数先执行)
- 比如你发送post请求就可以通过dispatch找到对应的post函数进行处理,get就会找到get函数处理
CBV:urls.py:
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^home/',views.Home.as_view()), #as_view是指定调用view的as_view这个方法固定写法
]
CBV:views.py:
from django.shortcuts import HttpResponse
from django.views import View
class Home(View):
'''使用CBV时必须要继承view父类'''
def dispatch(self, request, *args, **kwargs):
# 调用父类中的dispatch
result = super(Home,self).dispatch(request, *args, **kwargs)
# 使用result主动继承view父类,然后return就可以重写父类的dispath方法
return result
# 在这里使用get发来请求就会调用get方法,使用post发来请求就会调用post方法
def get(self,request):
print(request.method)
return HttpResponse('get')
def post(self,request):
print(request.method,'POST')
return HttpResponse('post')
CBC:指定某个视图函数不使用csrf验证:
from django.shortcuts import HttpResponse
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
class Home(View):
'''使用CBV时必须要继承view父类'''
@method_decorator(csrf_exempt) # 指定Home这个视图函数不使用csrf
def dispatch(self, request, *args, **kwargs):
# 调用父类中的dispatch
result = super(Home,self).dispatch(request, *args, **kwargs)
# 使用result主动继承view父类,然后return就可以重写父类的dispath方法
return result
# 在这里使用get发来请求就会调用get方法,使用post发来请求就会调用post方法
def get(self,request):
print(request.method)
return HttpResponse('get')
def post(self,request):
print(request.method,'POST')
return HttpResponse('post')
七. 前后端交互:提交数据、提交文件
index.html提交数据:
<form action="/login/" method="post" enctype="multipart/form-data">
<p>
<input type="text" name="user" placeholder="用户名">
</p>
{# 1、单选框,返回单条数据的列表 #}
<p>
男:<input type="radio" name="gender" value="1">
女:<input type="radio" name="gender" value="2">
张扬:<input type="radio" name="gender" value="3">
</p>
{# 2、多选框、返回多条数据列表 #}
<p>
男:<input type="checkbox" name="favor" value="11">
女:<input type="checkbox" name="favor" value="22">
张扬:<input type="checkbox" name="favor" value="33">
</p>
{# 3、多选,返回多条数据的列表 #}
<p>
<select name="city" multiple>
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">广州</option>
</select>
</p>
{# 4、提交文件 #}
<p><input type="file" name="fff"></p>
<input type="submit" value="提交">
</form>
views.py获取数据:
def login(request):
if request.method == 'GET':
return render(request,'login.html')
elif request.method == 'POST':
v = request.POST.get('gender') #1 获取单选框的value值
v = request.POST.getlist('favor') #2 获取多选框value:['11', '22', '33']
v = request.POST.getlist('city') #3 获取多选下拉菜单:['bj', 'sh', 'gz']
print(v.name,type(v))
#当服务器端取客户端发送来的数据,不会将数据一下拿过来而是一点点取(chunks就是文件分成的块)
obj = request.FILES.get('fff') #4 下面是获取客户端上传的文件(如:图片)
import os
file_path = os.path.join('upload',obj.name)
f = open(file_path,mode='wb')
for i in obj.chunks():
f.write(i)
f.close()
return render(request,'login.html')
request获取数据方式:
# 1、request.POST
# 2、request.GET
# 3、request.FILES
# 4、request.getlist
# 5、request.method
# 6、request.path_info #获取当前url
# 7、request.body #自己获取数据
# 8、a = ‘中国’
response = HttpResponse(a)
response[“name”] = ‘alex’ #HttpResponse不仅可以在响应头中传字符串,也可以传键值对
response.set_cookie() #设置cookie实质也是向请求头中传入键值对
八. Django生命周期与中间件
1、中间件处理过程
1、首先客户端发起请求,会将请求交给settings.py中排在最前面的中间件
2、前面中间件收到请求会调用类中的process_request方法处理,然后交给下一个中间件的process_request函数
3、到达最后一个中间件的process_request函数处理后会到达url路由系统
4、然后从路由系统直接跳转到第一个中间件的process_view函数,依次向后面中间的process_view传递,最后到达views.py处理函数,获取网页中的数据
5、获取的数据会交给最后一个中间件的process_response方法处理,然后依次向前面的中间件process_response方法提交请求的内容,最后由最前面的中间件将请求数据返回到客户端
6、在任一中间件的process_request和process_view方法中有返回值就会直接返回给process_response
2、生命周期图解
3、Django生命周期请求过程
1.客户端访问
- 客户端在浏览器中输入url路径访问指定网页
2. 请求发送给Django程序
1、首先会交给中间件,中间件处理后交给路由系统
2、路由系统
- Django程序会到urls.py文件中找到对应请求的处理函数(视图函数)
3、视图函数
- 视图函数会找到对应的html模板文件
- 然后到数据库中取得数据替换html模板中的内容
- 使用static中的js和css文件结合对html渲染
- 最后Django将最终渲染后的html文件返回给中间件
4、中间件再调用process_response方法处理,最后交给用户