本节内容
- Web框架本质
- Django 基础
- Django 进阶
一、Web框架本质
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
WEB框架本质是一个socket
#########WEB框架(代码文件结构)
MVC
Model View Controller
数据库 模板文件 业务处理
MTV
Model Template View
数据库 模板文件 业务处理
############## WEB:MVC、MTV
1、本质
import socket
#WEB框架本质-->socket
def handle_request(client):
buf = client.recv(1024)
client.send(b"HTTP/1.1 200 OK\r\n\r\n")
client.send(b"Hello, Seven")
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8000))
sock.listen(5)
while True:
connection, address = sock.accept()
handle_request(connection)
connection.close()
if __name__ == '__main__':
main()
2、自定义Web框架
WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。 Python标准库提供的独立WSGI服务器称为wsgiref(封装好的socket)。
通过Python标准库提供的wsgiref模块开发一个自己的Web框架。
1 from wsgiref.simple_server import make_server
2 from Controller import accout
3
4 URL_DICT = {
5 '/index': accout.handle_index,
6 '/data': accout.handle_data,
7 } #可以做正则匹配,匹配一类的请求内容
8
9 def RunServer(environ, start_response):
10 # environ 客户端发来的所有数据
11 # start_response 封装要返回给用户的数据,响应头状态
12 start_response('200 OK', [('Content-Type', 'text/html')])
13 current_url = environ['PATH_INFO']
14
15 # 返回的内容
16 func = None
17 if current_url in URL_DICT:
18 func = URL_DICT[current_url]
19 if func:
20 return func()
21 else:
22 return ['<h1>404</h1>'.encode('utf-8'), ]
23 else:
24 return ['<h1>404</h1>'.encode('utf-8'), ]
25
26 # if current_url == '/index':
27 # return handle_index()
28 # elif current_url == '/data':
29 # return handle_data()
30 # else:
31 # return ['<h1>404</h1>'.encode('utf-8'), ]
32
33 # return ['<h1>Hello, web!</h1>'.encode('utf-8'),]
34
35 if __name__ == '__main__':
36 httpd = make_server('', 8000, RunServer)
37 print("Serving HTTP on port 8000...")
38 httpd.serve_forever()
二、Django基础
Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
Django生存周期:
1 Django:用Python开发Web站点提供最齐全的Web框架,基于MTV的框架
2
3 pip3 install django
4
5
6 C:\Python35\Scripts
7
8 1、创建Django工程(可以使用Pycharm创建)
9 django-admin startproject 【工程名称】 --> 会在当前目录下生成Django工程目录
10 如:django-admin startproject mysite
11 默认创建如下内容
12 mysite
13 - mysite # 对整个程序进行配置
14 - init
15 - settings # 配置文件
16 - url # URL对应关系
17 - wsgi # 遵循WSIG规范,uwsgi + nginx(Django内部没有包含socket)
18
19 - manage.py # 管理Django程序:
20 - python manage.py
21 - python manage.py startapp xx
22 - python manage.py makemigrations
23 - python manage.py migrate
24
25 PS: WSGI (Web Server Gateway Interface)
26 是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。python标准库提供的独立WSGI服务器称为wsgiref。
27
28
29 2、运行Django功能(可使用Pycharm运行,添加Djangoserver)
30 python manage.py runserver 127.0.0.1:8001
31
32 ------------------
33 chouti
34 - chouti
35 - 配置
36 - 主站 app
37 - 后台管理 app
38 ------------------
39
40
41 3、创建app(进入Django工程根目录,执行如下命令)
42 python manage.py startapp cmdb
43 python manage.py startapp openstack
44 python manage.py startapp xxoo....
45
46 业务处理代码放入app中(views)
47 app:
48 migrations 修改表结构记录
49 admin Django为我们提供的后台管理
50 apps 配置当前app
51 models ORM,写指定的类 通过命令可以创建数据库结构
52 tests 单元测试
53 views 业务代码
54
55 4、配置(project.settings.py)
56
57 a、配置模板的路径
58
59 TEMPLATES = [
60 {
61 'BACKEND': 'django.template.backends.django.DjangoTemplates',
62
63 'DIRS': [os.path.join(BASE_DIR, 'templates')],
64
65 'APP_DIRS': True,
66 'OPTIONS': {
67 'context_processors': [
68 'django.template.context_processors.debug',
69 'django.template.context_processors.request',
70 'django.contrib.auth.context_processors.auth',
71 'django.contrib.messages.context_processors.messages',
72 ],
73 },
74 },
75 ]
76
77 b、配置静态目录(不要忘记逗号)
78 static --> 静态文件目录名字使用static
79
80 STATICFILES_DIRS = (
81 os.path.join(BASE_DIR, 'static'),
82 )
83
84 <link rel="stylesheet" href="/static/commons.css" />
85
86
87 c、CSRF verification failed. Request aborted 报错解决(settings文件内注释csrf)
88
89 MIDDLEWARE = [
90 'django.middleware.security.SecurityMiddleware',
91 'django.contrib.sessions.middleware.SessionMiddleware',
92 'django.middleware.common.CommonMiddleware',
93 #'django.middleware.csrf.CsrfViewMiddleware',
94 'django.contrib.auth.middleware.AuthenticationMiddleware',
95 'django.contrib.messages.middleware.MessageMiddleware',
96 'django.middleware.clickjacking.XFrameOptionsMiddleware',
97 ]
98
99 5、定义路由规则
100 url.py
101
102 "login" --> 函数名
103
104
105 6、定义视图函数
106 app下views.py
107
108 def func(request):
109 # request.method GET / POST -- 用户提交方式
110
111 # http://127.0.0.1:8009/home?nid=123&name=alex
112 # request.GET.get('',None) # 获取请求发来的而数据
113
114 # request.POST.get('',None)
115
116 # return HttpResponse("字符串") -- 返回字符串
117 # return render(request, "HTML模板的路径") -- 返回给用户模板
118 # return redirect('/只能填URL') -- 跳转,只能填'/URL'
119
120 7、模板渲染
121 特殊的模板语言
122
123 a、{{ 变量名 }}
124
125 视图函数:
126 def func(request):
127 return render(request, "index.html", {'current_user': "alex"})
128
129
130 模板:index.html
131 -----------
132 <html>
133 ..
134 <body>
135 <div>{{current_user}}</div>
136 </body>
137
138 </html>
139
140 ====> 最后生成的字符串
141
142 <html>
143 ..
144 <body>
145 <div>alex</div>
146 </body>
147
148 </html>
149 ------------
150
151 b、For循环
152 def func(request):
153 return render(request, "index.html", {'current_user': "alex", 'user_list': ['alex','eric']})
154
155
156 index.html
157 ------------
158 <html>
159 ..
160 <body>
161 <div>{{current_user}}</div>
162
163 <ul>
164 {% for row in user_list %}
165
166 {% if row == "alex" %}
167 <li>{{ row }}</li>
168 {% endif %}
169
170 {% endfor %}
171 </ul>
172
173 </body>
174
175 </html>
176 ------------
177
178
179 c、索引#################
180 def func(request):
181 return render(request, "index.html", {
182 'current_user': "alex",
183 'user_list': ['alex','eric'],
184 'user_dict': {'k1': 'v1', 'k2': 'v2'}})
185
186
187 index.html
188
189 <html>
190 ..
191 <body>
192 <div>{{current_user}}</div>
193
194 <a> {{ user_list.1 }} </a> #模板语言中根据索引获取列表内容
195 <a> {{ user_dict.k1 }} </a> #模板语言中根据索引获取字典内容
196 <a> {{ user_dict.k2 }} </a>
197
198 </body>
199
200 </html>
201
202
203 d、条件 ###################
204
205 def func(request):
206 return render(request, "index.html", {
207 'current_user': "alex",
208 "age": 18,
209 'user_list': ['alex','eric'],
210 'user_dict': {'k1': 'v1', 'k2': 'v2'}})
211
212
213 index.html
214
215 <html>
216 ..
217 <body>
218 <div>{{current_user}}</div>
219
220 <a> {{ user_list.1 }} </a>
221 <a> {{ user_dict.k1 }} </a>
222 <a> {{ user_dict.k2 }} </a>
223
224 {% if age %}
225 <a>有年龄</a>
226 {% if age > 16 %}
227 <a>老男人</a>
228 {% else %}
229 <a>小鲜肉</a>
230 {% endif %}
231 {% else %}
232 <a>无年龄</a>
233 {% endif %}
234 </body>
235
236 </html>
1、创建Django工程
可以使用Django在命令行中创建工程,也可以使用Pycharm创建(本质上自动执行了创建命令)
1 django-admin startproject 【工程名称】
2 如:django-admin startproject mysite
3 默认创建如下内容
4 - mysite # 工程
5 - mysite # 对整个程序进行配置
6 - __init__.py
7 - settings.py # 配置文件
8 - urls.py # URL对应关系
9 - wsgi.py # 遵循WSIG规范,wsgi + nginx(Django内部没有包含socket)
10
11 - manage.py # 管理Django程序:
12 - python manage.py
13 - python manage.py startapp xx
14 - python manage.py makemigrations
15 - python manage.py migrate
16
17 PS: WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。python标准库提供的独立WSGI服务器称为wsgiref。
2、运行Django功能
可以在命令行中启动,也可以使用Pycharm创建Django server来运行(在Pycharm中创建的Django工程默认添加了Django server)
1 python manage.py runserver 127.0.0.1:8001
2
3 ------------------
4 chouti
5 - chouti
6 - 配置
7 - 主站 app
8 - 后台管理 app
9 ------------------
10
11 PS:Python和Django要加环境变量
3、创建app
进入Django工程根目录,执行如下命令
1 python manage.py startapp cmdb
2 python manage.py startapp openstack
3 python manage.py startapp xxoo....
4
5 业务处理代码放入app中(views)
6 app:
7 migrations 修改表结构记录
8 admin Django为我们提供的后台管理
9 apps 配置当前app
10 models ORM,写指定的类 通过命令可以创建数据库结构
11 tests 单元测试
12 views 业务代码
4、配置文件
"""
Django settings for s14django project.
Generated by 'django-admin startproject' using Django 1.10.4.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.10/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'hut(bs^o50n^opj8yneen_sh)m0uvu#sdzr%&eq1x)5p*(tqcz'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'cmdb',
]
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 = 's14django.urls'
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',
],
},
},
]
WSGI_APPLICATION = 's14django.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
STATIC_URL = '/static/'
# 配置好static静态文件目录,不配置用户访问页面静态文件访问不到
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
# APPEND_SLASH=True
1) 配置HTML模板的路径
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',
],
},
},
]
2) 配置静态目录
static --> 静态文件目录名字使用static
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
<link rel="stylesheet" href="/static/commons.css" />
3) CSRF verification failed. Request aborted 报错解决
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',
]
4) 数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dbname',
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '',
'PORT': '',
}
}
# 注意:
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而Python3中还无此模块,所以需要使用pymysql模块来代替。
# 在project下与其同名文件夹下的 __init__.py文件中做如下设置
import pymysql
pymysql.install_as_MySQLdb()
5、路由规则
定义url与业务处理函数(视图函数)之间的映射关系。
1 URL拼接传递参数有两种方式:
2 - 在url后加"?key=value"拼接,可以在视图函数中通过get()获取,如:
3 html文件
4 <a class="detail" href="/index?nid=1">详细信息</a> #id是内置方法,尽量不要使用id做参数
5 ---
6 urls.py文件
7 url(r'^index/', views.index), #一个url对应函数
8 url(r'^home/', views.Home.as_view()), #一个url对应类,根据method通过反射来执行对应方法
9
10
11 - 在url后加"分隔符value"拼接,在urls.py中通过正则进行匹配(常用方法),如:
12 html文件
13 <a class="detail" href="/detail-2-9.html">详细信息</a>
14 ---
15 urls.py文件
16 a、一类url对应函数,"正则匹配"的数据(\d+)交给视图函数(视图函数参数有位置要求)
17 url(r'^detail-(\d+)-(\d+).html', views.detail),
18
19 def func(request, nid, uid): #nid即正则匹配的数据(\d+)
20 pass
21 def func(request, *args):
22 args = (2,9)
23 def func(request, *args, **kwargs):
24 args = (2,9)
25
26
27 b、"正则匹配"的数据"分组"(?P<nid>\d+)交给视图函数(视图函数参数没有位置要求)
28 url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)
29
30 def func(request, nid, uid):
31 pass
32
33 def funct(request, **kwargs):
34 kwargs = {'nid': 1, 'uid': 3}
35
36 def func(request, *args, **kwargs):
37 args = (2,9)
38
39
40 - PS:
41 def detail(request, *args,**kwargs):
42 pass
1 """s14django URL Configuration
2
3 The `urlpatterns` list routes URLs to views. For more information please see:
4 https://docs.djangoproject.com/en/1.10/topics/http/urls/
5 Examples:
6 Function views
7 1. Add an import: from my_app import views
8 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
9 Class-based views
10 1. Add an import: from other_app.views import Home
11 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
12 Including another URLconf
13 1. Import the include() function: from django.conf.urls import url, include
14 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
15 """
16 from django.conf.urls import url
17 from django.contrib import admin
18 from cmdb import views
19
20 urlpatterns = [
21 url(r'^admin/', admin.site.urls),
22 # url(r'^h.html/', views.home),
23 url(r'^login', views.login),
24 url(r'^home', views.home),
25 ]
1) 单一路由对应
from django.conf.urls import url
urlpatterns = [
url(r'^index/', views.index), #一个url对应函数
url(r'^home/', views.Home.as_view()), #一个url对应类,根据method通过反射来执行对应方法
]
from django.views import View
class Home(View):
#方法名必须小写,支持的方法见源码
def dispatch(self, request, *args, **kwargs):
# 调用父类中的dispatch,相当于装饰器功能
print('before')
result = super(Home,self).dispatch(request, *args, **kwargs)
print('after')
return result
def get(self,request):
print(request.method)
return render(request, 'home.html')
def post(self,request):
print(request.method,'POST')
return render(request, 'home.html')
2) 基于正则的路由
1 html文件
2 <a class="detail" href="/detail-2-9.html">详细信息</a>
3 ---
4 urls.py文件
5 a、一类url对应函数,"正则匹配"的数据(\d+)交给视图函数(视图函数参数有位置要求)
6 url(r'^detail-(\d+)-(\d+).html', views.detail),
7
8 def func(request, nid, uid): #nid即正则匹配的数据(\d+)
9 pass
10 def func(request, *args):
11 args = (2,9)
12 def func(request, *args, **kwargs):
13 args = (2,9)
14
15
16 b、"正则匹配"的数据"分组"(?P<nid>\d+)交给视图函数(视图函数参数没有位置要求)
17 url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)
18
19 def func(request, nid, uid):
20 pass
21
22 def funct(request, **kwargs):
23 kwargs = {'nid': 1, 'uid': 3}
24
25 def func(request, *args, **kwargs):
26 args = (2,9)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
margin: 0;
}
.menu{
display: block;
padding: 5px;
}
</style>
</head>
<body>
<div style="height: 48px;background-color: black;color: white">
红红火火哈哈
</div>
<div>
<div style="position: absolute;top:48px;bottom: 0;left: 0;width: 200px;background-color: brown;">
<a class="menu" href="/cmdb/user_info/">用户管理</a>
<a class="menu" href="/cmdb/user_group/">用户组管理</a>
</div>
<div style="position:absolute;top:48px;left: 210px;bottom: 0;right: 0;overflow: auto">
<h3>添加用户</h3>
<form method="POST" action="/cmdb/user_info/">
<input type="text" name="user" />
<input type="text" name="pwd" />
<select name="group_id">
{% for item in group_list %}
<option value="{{ item.uid }}">{{ item.caption }}</option>
{% endfor %}
</select>
<input type="submit" value="添加"/>
</form>
<h3>用户列表</h3>
<ul>
{% for row in user_list %}
<li>
<a href="/cmdb/userdetail-{{ row.id }}/">{{ row.username }}</a> |
<span> {{ row.user_group.caption }} </span>
<a href="/cmdb/userdel-{{ row.id }}/">删除</a> |
<a href="/cmdb/useredit-{{ row.id }}/">编辑</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</body>
</html>
3) 多级路由(include),根据app对路由规则进行分类
#project/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^cmdb/', include("app01.urls")),
url(r'^monitor/', include("app02.urls")),
]
#app01/urls.py
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^login/', views.login),
]
#app02/urls.py
from django.conf.urls import url,include
from django.contrib import admin
from app02 import views
urlpatterns = [
url(r'^login/', views.login),
]
4) 默认值
5) 命名空间
6、视图函数
处理用户请求函数,app目录下的views.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#上传文件form做处理enctype="multipart/form-data"#}
<form action="/login/" method="POST" enctype="multipart/form-data">
<p>
<input type="text" name="user" placeholder="用户名" />
</p>
<p>
<input type="password" name="pwd" placeholder="密码" />
</p>
<p>
男:<input type="radio" name="gender" value="1"/>
女:<input type="radio" name="gender" value="2"/>
</p>
<p>
男:<input type="checkbox" name="favor" value="11"/>
女:<input type="checkbox" name="favor" value="22"/>
</p>
<p>
<select name="city" multiple>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="tj">天津</option>
</select>
</p>
<p>
<input type="file" name="fafafa"/>
</p>
<input type="submit" value="提交"/>
</form>
</body>
</html>
1) 基本用法(一个url对应一个函数,一个url对应类的参照5-1)
1 app下views.py
2
3 def func(request):
4 # request.method GET / POST -- 用户提交方式
5
6 # http://127.0.0.1:8009/home?nid=123&name=alex
7 # request.GET.get('',None) # 获取请求发来的而数据
8
9 # request.POST.get('',None)
10
11 # return HttpResponse("字符串") -- 返回字符串
12 # return render(request, "HTML模板的路径") -- 返回给用户模板
13 # return redirect('/只能填URL') -- 跳转,只能填'/URL'
1 from django.shortcuts import render
2
3 # Create your views here.
4 from django.shortcuts import HttpResponse
5 from django.shortcuts import render
6 from django.shortcuts import redirect
7
8 def login(request):
9 # 包含用户提交的所有信息
10 # print(request.method) # 获取用户提交方法
11 error_msg = ""
12 #如果请求提交的方法是POST(用户提交的数据)
13 if request.method == "POST":
14 # 获取用户通过POST提交过来的数据(用户提交的数据类似于字典)
15 user = request.POST.get('user',None) #get('user',None)获取user内容,默认为None
16 pwd = request.POST.get('pwd',None)
17 if user == 'root' and pwd == "123":
18 # 去跳转到
19 return redirect('/login') #redirect重定向、跳转
20 else:
21 # 用户密码不配
22 error_msg = "用户名或密码错误"
23 #打开页面并返回给用户,settings文件中配置了html文件的路径TEMPLATES('DIRS': [os.path.join(BASE_DIR, 'templates')])
24 return render(request,'login.html', {'error_msg': error_msg}) #render找到模板返回给用户
25
26 USER_LIST = [
27 {'id': 1, 'username': 'alex', 'email': 'asdfasdf', "gender": '男'},
28 {'id': 2, 'username': 'eriuc', 'email': 'asdfasdf', "gender": '男'},
29 {"id": 3,'username': 'seven', 'email': 'asdfasdf', "gender": '男'},
30 ]
31
32 def home(request):
33 print(request.GET.get('nid'))
34
35 if request.method == "POST":
36 # 获取用户提交的数据 POST请求中
37 u = request.POST.get('username')
38 e = request.POST.get('email')
39 g = request.POST.get('gender')
40 temp = {'username': u, 'email': e, "gender": g}
41 USER_LIST.append(temp)
42 return render(request, 'test/home.html', {'user_list': USER_LIST})
43
44
45 # def login(request):
46 # # string = """
47 # # <form>
48 # # <input type='text' />
49 # # </form>
50 # #
51 # # """
52 # # f = open('templates/login.html', 'r', encoding='utf-8')
53 # # data = f.read()
54 # # f.close()
55 # # return HttpResponse(data)
56 # return render(request,'login.html')
57
58 # def home(request):
59 # return HttpResponse('<h1>CMDB</h1>')
60
61 # 主机管理
62 # 防火墙
63 # 。。。
2) 获取用户请求数据
request.GET.get()
request.POST.get()
request.FILES.get()
PS:
GET:http请求默认使用的method,获取数据
POST:可以与GET区分,用来提交数据
3) 获取多选的内容(checkbox等)
request.POST.getlist()
4) 上传文件
import os
from django.shortcuts import render,redirect
from django.core.files.uploadedfile import InMemoryUploadedFile
def login(request):
if request.method == "GET":
return render(request, 'login.html')
elif request.method == "POST":
# 上传文件,form标签做特殊设置
obj = request.FILES.get('fafafa')
print(obj,type(obj),obj.name)
#文件路径拼接
file_path = os.path.join('upload', obj.name)
# 打开文件
f = open(file_path, mode="wb")
# obj.chunks()上传文件的块数据
for i in obj.chunks():
f.write(i)
f.close()
return render(request, 'login.html')
else:
# PUT,DELETE,HEAD,OPTION...
return redirect('/index/')
5) FBV&CBV
FBV --> function base view
url.py
/index/ -> 函数名
view.py
def 函数(request):
...
CBV --> class base view
url.py
/index/ -> 类
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^home/', views.Home.as_view()), #根据get或post提交方式在类中执行对应的方法
]
view.py
from django.views import View
class Home(View):
def dispatch(self, request, *args, **kwargs):
# 调用父类中的dispatch
print('before')
result = super(Home,self).dispatch(request, *args, **kwargs)
print('after')
return result
def get(self,request):
print(request.method)
return render(request, 'home.html')
def post(self,request):
print(request.method,'POST')
return render(request, 'home.html')
PS:类的方法名一定要小写,源代码中定义好了方法名
====》
建议:两者都用
6) 装饰器
7、模板
templates目录下html
1) 模板的执行
模版的创建过程,其实就是读取模版(其中嵌套着模版标签),然后将 Model 中获取的数据插入到模版中,最后将信息返回给用户。
2) 模板语言
变量:
{{ item }}
For循环:
{% for item in item_list %} {{ item }} {% endfor %}
forloop.counter
forloop.first
forloop.last
if语句:
{% if ordered_warranty %} {% else %} {% endif %}
母板:
{% block title %}{% endblock %}
子板:
{% extends "base.html" %}
{% block title %}{% endblock %}
帮助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <link rel="stylesheet" href="/static/commons.css" />
7 <style>
8 label{
9 width: 80px;
10 text-align: right;
11 display: inline-block;
12 }
13 </style>
14 </head>
15 <body>
16 {#提交数据给login#}
17 <form action="/login" method="post">
18 <p>
19 {#点击label后input内出现光标#}
20 <label for="username">用户名:</label>
21 <input id="username" name="user" type="text" />
22 </p>
23 <p>
24 <label for="password">密码:</label>
25 <input id="password" name="pwd" type="password" />
26 <input type="submit" value="提交" />
27 {# Django会特殊处理 {{ error_msg }} #}
28 <span style="color: red;">{{ error_msg }}</span>
29 </p>
30 </form>
31 <script src="/static/jquery.min.js"></script>
32 </body>
33 </html>
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 </head>
7 <body style="margin: 0">
8 <div style="height: 48px;background-color: #dddddd"></div>
9 <div>
10 <form action="/home" method="post">
11 <input type="text" name="username" placeholder="用户名" />
12 <input type="text" name="email" placeholder="邮箱"/>
13 <input type="text" name="gender" placeholder="性别"/>
14 <input type="submit" value="添加" />
15 </form>
16 </div>
17 <div>
18 <table>
19 {# Django模板语言for循环 #}
20 {% for row in user_list %}
21 <tr>
22 <td>{{ row.username }}</td>
23 <td>{{ row.gender }}</td>
24 <td>{{ row.email }}</td>
25 <td>
26 <a href="/detail?nid={{ row.id }}">查看详细</a> |
27 <a class="del" href="#" row-id="{{ row.id }}">删除</a>
28 </td>
29 </tr>
30 {% endfor %}
31
32 </table>
33 </div>
34 <div>
35 <form action="/del_host" method="post">
36 <input style="display: none" id="nid" type="text" name="nid" />
37 <p>
38 <input type="submit" />
39 <input type="botton" />
40 </p>
41 </form>
42 </div>
43 <script>
44 $('.del').click(function(){
45 var row_id = $(this).attr('row-id');
46 //赋值
47 $('#nid').val(row_id);
48 })
49 </script>
50 </body>
51 </html>
1 def func(request):
2 return render(request, "index.html", {
3 'current_user': "alex",
4 'user_list': ['alex','eric'],
5 'user_dict': {'k1': 'v1', 'k2': 'v2'}})
6
7
8 index.html
9
10 <html>
11 ..
12 <body>
13 <div>{{current_user}}</div>
14
15 <a> {{ user_list.1 }} </a> #模板语言中根据索引获取列表内容
16 <a> {{ user_dict.k1 }} </a> #模板语言中根据索引获取字典内容
17 <a> {{ user_dict.k2 }} </a>
18
19 </body>
20
21 </html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#根据索引(key)直接获取值#}
{{ user_dict.k1 }}
<ul>
{#循环的key#}
{% for k in user_dict.keys %}
<li>{{ k }}</li>
{% endfor %}
</ul>
<ul>
{#循环的value#}
{% for val in user_dict.values %}
<li>{{ val }}</li>
{% endfor %}
</ul>
<ul>
{#循环的key和value#}
{% for k,row in user_dict.items %}
<li>{{ k }}-{{ row }}</li>
{% endfor %}
</ul>
</body>
</html>
1 def func(request):
2 return render(request, "index.html", {
3 'current_user': "alex",
4 "age": 18,
5 'user_list': ['alex','eric'],
6 'user_dict': {'k1': 'v1', 'k2': 'v2'}})
7
8
9 index.html
10 <html>
11 ..
12 <body>
13 <div>{{current_user}}</div>
14
15 <a> {{ user_list.1 }} </a>
16 <a> {{ user_dict.k1 }} </a>
17 <a> {{ user_dict.k2 }} </a>
18
19 {% if age %}
20 <a>有年龄</a>
21 {% if age > 16 %}
22 <a>老男人</a>
23 {% else %}
24 <a>小鲜肉</a>
25 {% endif %}
26 {% else %}
27 <a>无年龄</a>
28 {% endif %}
29 </body>
30
31 </html>
3) 自定义simple_tag
8、中间件
9、admin
三、Django进阶
Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
1、Model
django使用ORM方式处理数据库相关操作,ORM即,关系对象映射(Object Relational Mapping)。
PHP:activerecord
Java:Hibernate
C#:Entity Framework
django中遵循 Code Frist 的原则,即,根据代码中定义的类来自动生成数据库表。注意原生SQL与ORM的对应关系。
1) 创建表
*基本结构
a. 先写类
from django.db import models
# app01_userinfo
class UserInfo(models.Model):
# id列,自增,主键
# 用户名列,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
b. 注册APP
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01', #settings中添加app名,Django才给app生成数据库
]
c. 执行命令(同步结构改动到数据库)
#记录对models.py的改动(表结构变化),并在migrations下生成记录文件
python manage.py makemigrations
#将改动应用到数据库
python manage.py migrate
注意:缩小列长度要谨慎,超出长度数据会丢失
d. ********** 注意 ***********
Django默认使用MySQLdb模块链接MySQL
主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可:
import pymysql
pymysql.install_as_MySQLdb()
# Create your models here.
# app01_userinfo
from django.db import models
class UserGroup(models.Model):
uid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=32,unique=True)
ctime = models.DateTimeField(auto_now_add=True, null=True)
uptime = models.DateTimeField(auto_now=True, null=True)
class UserInfo(models.Model): #必须继承models.Model
# id列,自增,主键 (Djiango默认创建)
# 用户名列,字符串类型CharField,指定长度max_length
# 字符串、数字、时间、二进制
username = models.CharField(max_length=32,blank=True,verbose_name='用户名')
password = models.CharField(max_length=60, help_text='pwd')
email = models.CharField(max_length=60)
test = models.EmailField(max_length=19,null=True,error_messages={'invalid': '请输入密码'})
# user_group_id 数字
user_group = models.ForeignKey("UserGroup",to_field='uid',on_delete=models.CASCADE) # (uid,catption,ctime,uptimew)
user_type_choices = (
(1, '超级用户'),
(2, '普通用户'),
(3, '普普通用户'),
)
user_type_id = models.IntegerField(choices=user_type_choices,default=1)
#不同的字符串类型(...Field),给Django的admin表单认证使用的
# test = models.URLField(max_length=19,null=True)
# test = models.GenericIPAddressField()
# gender = models.CharField(max_length=60, null=True)
字符串********
不同的字符串类型,只是给Django的admin表单校验使用的(如自动校验EmailField是否是邮箱格式)
CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField(Field)
- 文本类型
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制(新版本中废弃,使用GenericIPAddressField)
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
数字********
AutoField(Field)
- int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列
---
from django.db import models
class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
自定义无符号整数字段
class UnsignedIntegerField(models.IntegerField):
def db_type(self, connection):
return 'integer UNSIGNED'
PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
BooleanField(Field)
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值
DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
二进制********
BinaryField(Field)
- 二进制类型
日期、时间********
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
auto_now_add 创建时,自动生成时间
auto_now 更新时,自动更新为当前时间
# obj = UserGroup.objects.filter(id=1).update(caption='CEO') #自动时间更新不生效
# obj = UserGroup.objects.filter(id=1).first() #生效
# obj.caption = "CEO"
# obj.save()
default 数据库中字段的默认值
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
db_tablespace
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中字段名显示自定义的名字
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的输入提示信息(显示在该行下边)
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
注:因为数据存在内存中,如果修改要重启程序才会生效
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "table_name"
# 联合索引
index_together = [
("pub_date", "deadline"),
]
# 联合唯一索引
unique_together = (("driver", "restaurant"),)
# admin中显示的表名称
verbose_name
# verbose_name加s
verbose_name_plural
#更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
1.触发Model中的验证和错误提示有两种方式:
a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
b. 调用Model对象的 clean_fields 方法,如:
# models.py
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
email = models.EmailField(error_messages={'invalid': '格式错了.'})
# views.py
def index(request):
obj = models.UserInfo(username='11234', email='uu')
try:
print(obj.clean_fields())
except Exception as e:
print(e)
return HttpResponse('ok')
# Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
2.Admin中修改错误提示
# admin.py
from django.contrib import admin
from model_club import models
from django import forms
class UserInfoForm(forms.ModelForm):
username = forms.CharField(error_messages={'required': '用户名不能为空.'})
email = forms.EmailField(error_messages={'invalid': '邮箱格式错误.'})
age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})
class Meta:
model = models.UserInfo
# fields = ('username',)
fields = "__all__"
class UserInfoAdmin(admin.ModelAdmin):
form = UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)
*连表结构
2) 操作表
*基本操作
根据类对数据库表中的数据进行各种操作
一对多:
a. 创建外键(一个对象)
b. 数据库中实际存储 --> 外键字段_id
c. 根据"外键字段_id"添加数据
models.tb.object.create(name='root', user_group_id=1)
d. 显示用户组信息
userlist = models.tb.object.all()
for row in userlist:
row.id
row.user_group_id
row.user_group.caption
*进阶操作
*其他操作
*连表操作
*扩展
2、Form
3、跨站请求伪造
4、Cookie
5、Session
6、分页
7、缓存
8、序列化
9、信号
参考:
Web框架:http://www.cnblogs.com/wupeiqi/articles/5237672.html
Django【基础篇】:http://www.cnblogs.com/wupeiqi/articles/5237704.html
Django【进阶篇】:http://www.cnblogs.com/wupeiqi/articles/5246483.html
来源:oschina
链接:https://my.oschina.net/u/4393854/blog/4032245