Django-1.基础篇

Django

Django是什么?简单来说Django就是Python下的一种WEB框架,是一种MTV模型。Python有很多优秀的WEB框架,如Tornado,Flask,Web2py等。

框架(Framework)解决一个开发性问题而设计的具有一定约束的支撑结构,使用框架可以帮你快速开发特定的系统,简单说,就是别人搭建好的舞台你来表演。对于所有的web应用,本质上就是一个socket服务器,用户的游览器就是一个socket客户端

1
2
3
4
最简单的web应用就是把HTML用文件保存好,一个现成的HTTP服务器软件,接受用户请求,从文件中读取HTML,返回。
如果要动态生成HTML,就需要把上述步骤自己来实现,不过,接受HTTP请求,解析HTTP请求,发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态html,就花费大量时间去读http规范.
正确的做法是底层代码由专门的服务器软件实现,我们用python专注于生成HTML文档,因为我们不希望接触TCP连接,http原始请求和响应格式,索引需要一个统一的接口,专心用python写web业务.
这个接口叫做WSGI,web server gateway interface

在学习Django前我们需要对HTTP协议有个简单的了解。

HTTP

超文本传输协议,规定了游览器和服务器之间通讯规则,规定客户端 请求 服务器 以及 服务端 响应 客户端 的内容格式

客户端 ====请求(request)====>服务端

服务端====响应(response)====>客户端

请求协议

请求协议方法有很多种,比如GET,POST,HEAD,PUT,DELETE,CONNECT等。

其中最常用的方法只有GET/POST这两种方法:

如:http://www.baidu.com/index.html

请求协议格式如下:

请求首行 GET/index HTTP/1.1

请求头信息 为key:vlaue模式,如HOST:localhost

空行 用来和请求分开

请求体 GET没有请求体,POST有请求体

GET和POST区别:

GET:没有请求体,如果有则是在URL后体现出(暴露在URL后面导致不安全),请求体内容限制在1k以内,游览器默认使用GET请求方法

POST方法:有请求体,数据不会出现在地址栏中,请求体内容没有上限。

响应协议

响应格式如下:

响应首行

响应头信息

空行

响应体

响应内容是由服务器发给游览器内容,游览器器会根据响应内容来显示

实例

比如访问www.zhuxyid.com

可以使用chrome游览器的开发者模式查看响应内容。

General 整体信息

Request URL:客户端请求地址

Request Method:请求方法

Status Code:服务放回状态码

Remote Address:服务器IP

Referrer Policy:来源协议

Response Headers 响应头信息 服务端–>游览器

Connection:返回连接状态

Content-Length:返回响应字节长度

Content-Type:返回响应类型以及编码格式

Date:返回响应时间,通常都是GMT时间,并不是UTC时间

Server:返回WEB服务器类型,这里是nginx

X-Cache:这里是我在Nginx上开启缓存来查看命中率的

X-FRAME-Option:这里说明是否允许一个页面可否在<iframe></iframe>中标记。

Request Headers 请求头信息 游览器–>服务端

Accept:告知服务端接受格式或者类型,q=0.8表示权重比例最高

Accept-Encoding: 告知服务端压缩类型

Accept-Language: 告知服务端接受的语言

Connection: 告知服务端访问后是否立即端口,keepalive表示不立即端口,默认3s

Cookie: Cookie信息,后期详细介绍

Host: 服务端的域名

User-Agent 客户端信息(操作系统,游览器版本,游览器内核等)

简单的web框架实例

实现一个简单的web框架呢

1
WSGI服务器是python内部服务器,可以用wsgiref模块来来实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from wsgiref.simple_server import make_server
def webservers(environ,start_response):
# print(environ)
print(environ['PATH_INFO'])
# for k,v in environ.items():
# print('{}==>{}'.format(k,v))
# print(start_response)
start_response('200 OK',[('Content-Type','text/html')])
return [b'<h1>Hello,Web Server!</h1>']
httpd = make_server('127.0.0.1',8888,webservers)
print('Serving HTTP on port 8888....')
httpd.serve_forever()

application() 函数就是符合WSGI标准的一个HTTP处理函数,他接受两个函数
#environ #一个包含所有HTTP请求信息的dict对象(接受)
#start_response #一个发送HTTP响应函数

#在application()函数中,调用:start_response('200 OK',[('Content-Type','text/html')])
#就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数
#start_response()函数接受两个参数:
# 一个HTTP响应状态码
# 一个是一组list表示HTTP的Headr(每个Header用一个包含两个str的tuple表示)
简单多URL实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from wsgiref.simple_server import make_server
def static():
with open("web/index1.html",'rb') as f:
data = f.read()
return data
def error():
with open("web/404.html",'rb') as f:
data = f.read()
return data
def application(environ,start_response):
start_response('200 ok',[('Content-Type','text/html')])
#判断URI是那个字段
# for k,v in environ.items():
#根据URL返回输入的URI
# INFO = environ['PATH_INFO']
# return b'<h1>Hello,{}</h1>'.format(INFO)
#判断URI是否是zhuxy
# if environ['PATH_INFO'] == '/zhuxy':
# return b'<h1>HELLO Zhuxy,welcome your system'
# else:
# return b'<h1>404,HAHAH'
#返回html文本
if environ['PATH_INFO'] == '/zhuxy':
return [static()]
else:
return [error()]

httpd = make_server('127.0.0.1',8888,application)
print('Serving HTTP on port 8888....')
httpd.serve_forever()
简单路由功能实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from wsgiref.simple_server import make_server
def login(req):
with open("web/login.html",'rb') as f:
data = f.read()
return data
def logout(req):
with open("web/logout.html",'rb') as f:
data = f.read()
return data
def zhuxy(req):
with open("web/zhuxy.html",'rb') as f:
data = f.read()
return data
def router():
url_patterns = [
("/login",login),
("/logout",logout),
("/zhuxy",zhuxy)
]
return url_patterns

def application(environ,start_response):
start_response('200 ok',[('Content-Type','text/html')])
url_patterns = router()
func = None
for item in url_patterns:
if item[0] == environ['PATH_INFO']:
func = item[1]
break
return [func(environ)]

httpd = make_server('127.0.0.1',8888,application)
print('Serving HTTP on port 8888....')
httpd.serve_forever()

MVC和MTV

所谓MVC就是分为模块,视图,控制器三层,之间以插件式或者松耦合的方式连接在一起。

M(Model):主要负责业务对象于数据对象(ORM)

V(View):主要负责与用户的交互(page)

C(Controller):负责接收用户输入调用模型和视图完成用户操作

MVC模型

Django的模式是MTV,本质上于MVC差别不大,也是各组件保持松耦合关系,只是定义上有些不同。详见官方说明

M(Model):主要负责业务对象与数据库对象(ORM)

T(Template):模板,主要负责如何把页面展示给用户

V(View):视图函数,负责业务逻辑,通过View调用Model和Template

*Django提供一个URL分发器,将URL页面分发给不同View处理,View在调用响应的Model和Template

MTV模型

Django安装

直接使用pip install django来安装

Django常用命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
django-admin startproject mysite	#创建mysite项目
django-admin startapp myapp #创建myapp应用
#通常一个项目有很多应用,比如微信这个项目地下有小程序,支持等等应用,创建应用需要在项目创建后生成的目录下创建

**实例**
#比如创建一个www.zhuxyid.com这个网站项目,网站里面有博客,简历等系统
django-admin startproject myweb
--|manage.py #每创建一个项目都会自动生成一个用于管理项目脚本文件,比如check,flush,makemigrations,migrate,run等
--|myweb #项目名称,主要设置项目,比如静态页面路径,日志,数据库配置等
----|__init__.py #空文件,只是告知该文件被视为python包
----|settings.py #该项目配置文件
----|urls.py #URL声明
----|wsgi.py #与wsgi兼容的web服务器入口点。
--|templates #静态文件保存位置,如果使用命令行创建项目需要手动创建,

django-admin startapp blog
--|manage.py
--|myweb
--|templates
--|blog #应用路径,存放view和models
----|migrations #数据库生成脚本路径,当执行python manage.py makemigrations就有脚本文件存放在这里
----|__init__.py
----|admin.py #后台管理数据
----|apps.py
----|models.py #定义数据库文件
----|tests.py #测试单元
----|views.py #定义视图函数

#manage.py脚本常用命令:
#格式:python manage.py command
check 检查项目完整性
test 检查项目语法等问题
dbshell 进入django dbshell数据库交互
shell 进入django shell交互模式
dumpdata 导出数据
flush 清空数据
createsuperuser 创建超级管理员用户
changepassword 修改密码
makemigrations 生成数据库同步脚本
migrate 同步至数据
showmigrations 查看生成数据库同步脚本
showmigrate 查看同步至数据库SQL语句
clearsessions 清空session信息
runserver 启动django

Django配置文件说明

settings.py 介绍
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#cat myweb/myweb/settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#定义项目的绝对路径,os.path.abspath(__file__)指的是settings.py文件路径
SECRET_KEY = 'zpcl_2ui5$z+2rk@=jqk4u2u4aj9zfk7j3vcux_339p#z=8kz4'
#django安装的秘钥,提供加密签名,不可预测的值
DEBUG = True #开启DEBUG模式
ALLOWED_HOSTS = [] #允许主机地址
INSTALLED_APPS = [ #激活的django应用名称
'django.contrib.admin',
#管理站点
'django.contrib.auth',
#认证系统
'django.contrib.contenttypes',
#内容类型的框架
'django.contrib.sessions',
#会话框架
'django.contrib.messages',
#消息传递框架
'django.contrib.staticfiles',
#管理静态文件框架
'blog.apps.BlogConfig',
#blog应用
]

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',
]

ROOT_URLCONF = 'myweb.urls' #定义url,这里是项目的urls.py文件
TEMPLATES = [ #定义django的template路径
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
#定义的template路径
,
'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',
],
},
},
]
WSGI_APPLICATION = 'myweb.wsgi.application' #定义wsgi接口程序在myweb项目下的wsgi的application方法
DATABASES = { #定义数据库配置,django默认使用sqlite3,可以改成其他类型数据库
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
LANGUAGE_CODE = 'en-us' #语言
TIME_ZONE = 'UTC' #时区
USE_I18N = True #是否启用django翻译系统
USE_L10N = True #是否启用数据的本地化格式
USE_TZ = True #django使用市区钢制日期时间
STATIC_URL = '/static/' #静态文件别名
STATICFILES_DIRS=( #定义django的STATIC_URL别名具体物理路径。建议每个app都有单独的静态文件目录
os.path.join(BASE_DIR,"static"),
)
urls.py 介绍

在settings.py定义了ROOT_URLCONF = 'myweb.urls',这个就是django的路由系统

它的本质就是URL模块以及为该URL模式调用的函数视图之间的映射表,以这种方式告知django。一个URL对于一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#格式如下
urlpatterns = [
path(正则表达式,views视图函数,参数,别名)
]
#一个正则表达式字符串
#一个可调用对象,通常为视图函数,或者一个指定视图函数路径字符串
#可选的要传给视图函数的默认参数(字典类型)
#一个可选的别名参数


#默认的urls.py如下
$cat myweb/myweb/urls.py
from django.contrib import admin
from django.urls import path

urlpatterns = [
path('admin/', admin.site.urls),
#默认会有个admin管理页面,当启动django可以进入admin下,前提需要设置账号密码
]

#URL可以分发到每个应用
#需要导入include('path_urls')

项目实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
$django-admin startproject website
$django-admin startapp blogs

#settings.py
$cat website/website/settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS=(
os.path.join(BASE_DIR,"blogs","static"),
)

#项目下的urls.py
$cat website/website/urls.py
from django.contrib import admin
from django.urls import path,include
from blogs import views
urlpatterns = [
path(r'^admin/', admin.site.urls),
path(r'^showtime/', views.showtime),

path(r'article/(\d{4})',views.article_year),
#这里(\d{n})就是传入的参数,views里面的article_year函数需要接受

path(r'article/(\d{4})/(\d{2})/(\d{2})',views.article_year),
#这里如果传入多个参数,那么views里面article_year函数需要接受多少

path(r'test/(\w+)',views.test),
#上面叫 无命名分组,只是分组,没有命名

path(r'article1/(?P<year>\d{4})/(?P<mon>\d{2})/(?P<day>\d{2})',views.article1),
#上面叫 有命名分组,分组也命名,article1里面接受内容要与这里分组定义的名称一样

path(r'register',views.register,name="reg"),
#name= 指定别名,这里别名定义了,前端就可以直接掉这个register的views了

path(r'^blog/',include('blogs.urls')),
#以blog/的内容都分发到blogs.urls里面
]

#应用下的urls.py
$cat website/blogs/urls.py
from django.urls import path
from blogs import views
urlpatterns = [
path(r'register',views.register,name="reg"),
path(r'article1/(?P<year>\d{4})/(?P<mon>\d{2})/(?P<day>\d{2})', views.article1),
path(r'test/(\d+)',views.test),
path(r'login',views.login),
]

#应用下views.py
$cat website/blogs/views
from django.shortcuts import render,HttpResponse,redirect
import time,pymysql
def showtime(request):
systime = time.ctime()
return HttpResponse(systime)
#当用户直接通过url/showtime就可以显示时间了
def showtime(request):
systime = time.ctime()
return render(request,'index.html',{'systime':systime})
#也可以返回页面,页面显示时间,传递systime变量
#render和HttpResponse基本差不多只是做了一个渲染,HttpResponse返回值,render返回template
def reder(request,template_name):
return HttpResponse(content,content_type,status)

def article_year(request,y,m,d):
return HttpResponse('article from date:{}-{}-{}'.format(y,m,d))
#也可以接受多个值

def article1(request,year,mon,day):
return HttpResponse('article1 from year:{} mon:{} day:{}'.format(year,mon,day))
#path(r'article1/(?P<year>\d{4})/(?P<mon>\d{2})/(?P<day>\d{2})',views.article1),
#这里是命名

def test(request,text):
print(request.path)
print(request.get_full_path())
systime = time.ctime()
name = 'zhuxy'
return render(request,"index.html",locals())
#locals()表示传递所有变量

def register(request):
if request.method == "POST":
if request.POST.get('user') == 'zhuxy' and request.POST.get('passwd') == '19900919':
return redirect('blogs/login/')
return render(request,'register.html')

def login(request):
name = 'zhuxy'
job = 'ops'
return render(request,'login.html',locals())


#template文件
$cat index.html
<h3>Server Time: {{ systime }}</h3>
<h3>welcome come :{{name}}</h3>
#这里直接{{args}}调用views传入的值

$cat register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% load staticfiles %}
<title>用户注册</title>
</head>
<body>
<!--
<form action="http://127.0.0.1:8888/register" method="get">
这里写死了,提交就走register函数-->
<form action="/register" method="post">
就算这里不写django也会帮你添加ip+port-->
<form action="http://127.0.0.1:8888/register" method="post">
这里如果post,需要关闭django中的 setting中的'django.middleware.csrf.CsrfViewMiddleware',
-->
<form action="{% url 'reg' %}" method="post">
#这里如果post,需要关闭django中的 setting中的'django.middleware.csrf.CsrfViewMiddleware',
<h1>用户注册</h1>
<p>用户名 : <input type="text" name="user"></p>
<p>密 码 : <input type="text" name="passwd"></p>
<p>部 门 : <input type="checkbox" name="job" value="ops">运维
<input type="checkbox" name="job" value="qa">测试
<input type="checkbox" name="job" value="java">开发-JAVA
<input type="checkbox" name="job" value="front">前端-FRONT
<input type="checkbox" name="job" value="php">开发-PHP
<p><input type="submit"></p>
</form>
</body>
</html>


$cat login.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>user login info</title>
</head>
<body>
<h1>hello {{ name }}</h1>
<h1>your jobs: {{ job }} </h1>
</body>
</html>
看完了?赏个鸡腿钱,谢谢老板!