动静态网页
静态网页:数据是写死的,不会变化,除非直接修改html文件
动态网页:数据是动态获取的,例如获取当前时间,或者从数据库中获取数据,当数据库中的数据被修改后,会将被修改的数据动态展示到网页中。
jinja2模块
提供了一个可以在html页面上书写类似于python后端的代码 来操作数据(模板语法)
安装:pip3 install jinja2
flask框架模板语法使用的就是jinja2模块,所以你只要下了flask框架 就会自动下载jinja2
模板语法是在后端实现的,前端不识别。
模板语法:
<-- 模板语法(jinja2模板语法非常贴近python语法 但是并不是所有的框架使用的都是jinja模板语法) /-->
写在html文件中
{{ xxx }}
<p>{{xxx.username}}</p>
<p>{{xxx['password']}}</p>
<p>{{xxx.get('hobby')}}</p>
<p>{{xxx.get('hobby')[0]}}</p>
<p>{{xxx.get('hobby').1}}</p>
for循环:
{%for user_dict in xxx %}
<tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.name }}</td>
<td>{{ user_dict.hobby }}</td>
</tr>
{% endfor %}
手写web简易框架
处理请求的代码:
import socket
server = socket.socket()
server.bind(('localhost', 8080))
server.listen(5)
"""
请求首行
b'GET / HTTP/1.1
请求头
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空行,代表不再有请求头
下面是请求体,因为是get请求,因此请求体无数据
"""
while True:
conn, addr = server.accept()
# 将请求体转为字符串格式
data = conn.recv(1024).decode('utf-8')
conn.send(b'HTTP/1.1 200 OK
')
# 对转换后的数据进行切分(依据空格切分),获取到请求的路径
target_url = data.split(' ')[1]
if target_url == '/index':
conn.send(b'index')
elif target_url == '/login':
# 如果路径为/login就返回html文件
with open('login.html', 'rb') as f:
conn.send(f.read())
else:
# 如果请求页面不存在,返回404响应状态码
conn.send(b'404 NOT FIND')
conn.close()
引用的login.html文件内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<p>is login...</p>
</body>
</html>
基于wsgire模块手写简易版web框架
我们可以发现上面的代码,如果browser客户端请求的路径有上百个,我们就需要写上对应数量的if语句,以及对应的返回数据,这样程序的可扩展性差,且所有的判断和返回的数据都在一个文件中,显得杂乱。
根据功能不同拆分成不同的文件,用户可以在browser窗口中输入url之后可以获取到对应的资源。
文件拆分:
urls.py
:路由与视图函数的对应关系
views.py
:里面放视图函数(视图函数可以是函数也可以是类)
templates文件夹
:模板文件夹(里面存放的就是一堆html文件)
views.py中代码
:
def index(env):
return 'index'
def login(env):
return 'login'
def error(env):
return '404 NOT FIND'
import time
# 该函数需要返回一个html页面
def get_time(env):
current_time = time.strftime('%Y-%m-%d %X')
with open(r'G:python项目day49 emplates 2 get_time.html', 'r', encoding='utf-8') as f:
data = f.read()
data = data.replace('gfdgsfdgfdsgsfdgsfdgsfdgsdg', current_time) # 利用字符串的替换
return data
from jinja2 import Template
def get_user(env):
user_dict = {'username': 'jason', 'password': 123, 'hobby': ['read', 'study', 'run']}
with open(r'G:python项目day49 emplates 3 get_user.html', 'r', encoding='utf-8') as f:
data = f.read()
temp = Template(data)
res = temp.render(xxx=user_dict)
return res
import pymysql
def get_info(env):
conn = pymysql.connect(
host='127.0.0.1',
port='3306',
user='root',
password='123',
database='day49',
charset='utf-8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = "select * from userinfo"
cursor.execute(sql)
data = cursor.fetchall() # 返回的数据是列表套字典
# 将列表套字典的结构数据 直接传递给html页面
with open(r'G:python项目day49 emplates 4 get_info.html', 'rb', encoding='utf-8') as f:
data = f.read()
# 利用jinja2模块
tmp = Template(data)
# 利用对象的render方法 将数据直接传递给html页面
res = tmp.render(xxx=data)
return res
urls.py中代码:
from views import *
urls = [
('/index',index),
('/login', login),
('/get_time', get_time),
('/get_user', get_user),
('/get_info', get_info)
]
templates文件夹
:
python三大主流web框架
Django
优点:大而全,自身携带的组件特别多
缺点:笨重
flask(源码600多行,分为两部分:请求上下文,应用上下文)
优点:小而精,自身携带的组件和功能少,但第三方支持该框架的模块特别多,如果全部叠加起来可以超越django
缺点:第三方模块不是flask写的,随着flask的版本更新,第三方模块需要去兼容flask,会引发兼容性问题,因此受限于第三方模块
tornado
异步非阻塞
天然支持高并发
Django框架部署准备
windows安装注意事项:
- 计算机名称不能有中文
- python解释器的版本不能超过3.7(3.7的版本有bug)
- 推荐使用1.x版本(1.11.09~1.11.13)
如果你已经按照过不需要手动卸载 重新安会自动先卸载之前的版本再安装
安装命令:
# 在cmd窗口中执行
pip3 install django==1.11.11
# 临时使用其他源安装
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn django==1.11.11
测试是否安装成功:
# 命令行中输入
django-admin
如何创建django项目
命令行
# 先切换到要创建django项目的目录下
cd project
# 执行创建项目的命令
django-admin startproject mysite # mysite:项目名
# 此时会在项目文件下出现以下文件和目录
D:.
│ manage.py
│
└─mysite
settings.py
urls.py
wsgi.py
__init__.py
# 启动django项目(先切换到项目目录下)
python manage.py runserver # django的默认端口号8000
# 此时可以在浏览器中输入ip加端口号访问django
# 例如:http://127.0.0.1:8000/
# 打开的网页提示你创建独立功能的app
# python manage.py startapp [app_label]
python manage.py startapp app01
# 此时会多出来一个app1目录
目录: D:mydjangomysite
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2020/1/3 19:54 app01
d----- 2020/1/3 19:50 mysite
-a---- 2020/1/3 19:50 12288 db.sqlite3
-a---- 2020/1/3 19:36 826 manage.py
# cd 到app1中,查看目录
cd app01
# app1中的目录
卷序列号为 0FD0-081A
D:.
│ admin.py
│ apps.py
│ models.py
│ tests.py
│ views.py
│ __init__.py
│
└─migrations
__init__.py
注意点:
1、使用命令行创建的django项目是不会自动创建templates摸版本文件夹 你只能自己手动创建
2、命令行创建的django项目不但没有templates文件夹配置文件中也没有填写路径,而pycharm创建的会自动添加
如果不做这步操作,后面导入html文件时,路径需要写全路径,无法直接引用html文件
因此我们要去手动创建templates文件夹:
# 在项目目录下执行,就是和manage.py文件同级的目录
mkdir templates
手动将创建的目录添加到配置文件中:
# settings.py 在项目配置文件中第54行修改
# 修改TEMPLATES中的'DIRS': [os.path.join(BASE_DIR, 'templates')]
需要将创建的app在settings中INSTALLED_APPS注册上
# 我们创建的app也必须先在这个地方注册之后才能正常执行
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 注册我们自己的app
# 'app01' # 简写
'app01.apps.App01Config' # 完整写法
]
此时可以在urls.py中添加路由和视图的关系
# 这里的urls.py可以使用settings.py目录下的同级urls.py,也可以在我们创建的应用app01下新建urls.py
# 这里我们使用settings.py同级目录下的urls.py
from django.conf.urls import url
from django.contrib import admin
# 导入我们创建的app01中的视图函数文件
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 新增以下的路由和视图的关系
url(r'^index/', views.index),
url(r'^login/', views.login),
url(r'^home/', views.home),
]
再去app01目录下views.py文件中,创建我们的视图函数
# 将render,HttpResponse,redirect导入
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
# 定义的视图函数都必须传入request
def index(request):
return HttpResponse('你好啊小妹妹')
def login(request):
return render(request, 'login.html', {'user_dic': {'username': 'json', 'password': 123}, 'mes': 'hello'})
def home(request):
return redirect('https://www.baidu.com')
login.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#取字典中的值#}
{{ user_dic.username }}
</body>
</html>
pycharm快速创建
点击导航条上方的File ---> New Project ---> Django(此处注意不要使用虚拟环境,也不要取消勾选Enable Django admin) ---> Create ---> New Window ---> 完成
django的settings.py文件
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 1.11.11.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/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.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'lb2x()gw&p)10ob6=zky-9_62)fmy#-+m06)kzp8gi+6d*hv18'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
# 已经安装过的app
# 我们创建的app也必须先在这个地方注册之后才能正常执行
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 注册我们自己的app
# 'app01' # 简写
'app01.apps.App01Config' # 完整写法
]
# 中间件
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 = 'mysite.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 = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.11/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.11/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.11/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.11/howto/static-files/
STATIC_URL = '/static/'
django使用时注意点
- 代码修改了始终没有效果
- 在同一个端口下起来多个服务,一直跑的是最开始的那个服务
- 浏览器缓存问题
- django能够自动重启,但是他的重启机制只要检测到你的代码有变化,在一定时间间隔内就会自动重启,所以有时候可能会出现你的代码还没写完,就已经自动重启了。
django小白必回三板斧
HttpResponse
返回的是字符串
def index(request):
return HttpResponse('你好啊小妹妹')
render
返回html页面 并且可以给html页面传数据
def login(request):
return render(request, 'login.html', {'user_dic': {'username': 'json', 'password': 123}, 'mes': 'hello'})
# 返回html页面,并可以给html传入字典
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#取字典中的值#}
{{ user_dic.username }}
</body>
</html>
redirect
重定向
def home(request):
return redirect('https://www.baidu.com')