python之Djiango框架简介

基础

# HTTP响应状态码
    10X:服务端已经接受到你的数据了 你可以继续提交数据进行下一步操作
    20X:请求成功(200)
    30X:重定向(301,302)
    40X:请求错误(404)
    50X:服务端错误(500)

# GET请求与POST请求
        GET请求:获取页面资源
        POST请求:朝服务端发送数据(让服务端校验该数据)

一、Web框架本质

  所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端

根据不同的路径返回不同的内容

  可以写几个简单页面,然后通过http://127.0.0.1:8080/页面名称  来访问对应的页面测试

import socket

server = socket.socket()  # 默认是TCP协议
server.bind(('127.0.0.1',8080))  # 绑定IP端口
server.listen(5)  # 监听 半链接池:保护计算机安全

while True:
    conn, addr = server.accept()   # 等待连接
    data = conn.recv(1024)         # 接收客户端信息
    # 遵循HTTP协议,给回应的消息加上响应状态行
    conn.send(b'HTTP/1.1 200 OK

')
    res = data.decode('utf-8')
    current_path = res.split('
')[0].split(' ')[1]  # 字符串切割,获取路径
    # print(current_path)
    # 根据不同的路径返回不同的内容
    if current_path == '/index':
        # conn.send(b'index')
        with open('templates/111.html','rb') as f:
            conn.send(f.read())
    elif current_path == '/login':
        conn.send(b'login')
    else:
        conn.send(b'404')
    conn.close()

浏览器访问页面请求信息:

  HTTP协议主要规定了客户端和服务器之间的通信格式

  响应相关信息可以在浏览器调试窗口的network标签页中看到。可以根据view信息切割获得需要请求的页面

请求首行
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/75.0.3770.142 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cookie: csrftoken=3vPenhmlRQb8Tvl4okwYM0OZpDCl3P7rbxvfpRDOHJy1zUApw89ugxM6OZSxhIBM



请求体
'
http://127.0.0.1:8080/index
view展开:

根据不同的路径返回不同页面请求---函数版

import socket

sk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()

# 将不同的内容部分封装成函数
def index(url):
    # 读取index.html页面内容
    with open("index.html",'rb',encoding="utf-8") as f:
        s = f.read()
    # 返回字节数据
    return bytes(s,encoding="utf-8")

def login(url):
    with open("login.html",'rb',encoding="utf-8") as f:
        s = f.read()
    return bytes(s, encoding="utf-8")

list1= [
    ("templates/111.html","/index"),
    ("templates/login.html",'/login'),
]

while True:
    # 等待连接
    conn,add = sk.accept()
    data = conn.recv(1024) # 接收客户端发来的消息
    # 从data 中获取路径
    data = str(data,encoding='utf-8') # 把收到的字节类型数据转换成字符串
    print("data>>>",data)
    # 按
切割,url是从浏览器发过来的消息中分离出来的访问路径
    url = data.split("
")[0].split(' ')[1]
    print("url>>>>",url)
    conn.send(b'HTTP/1.1 200 OK

') #遵循http协议,所以回复的消息也要加状态行
    # 根据不同的路径返回不同内容,reponse是具体的响应体
    func = None
    for i in list1:
        if i[0].split("/")[1] == url:
            func = i[1]
            break
    # print("func>>>",func)
    if func:
        reponse = func(url)
    else:
        reponse = b"404 not found!"

    conn.send(reponse)
    conn.close()

# 还有点问题//TODO
View Code

 二、服务器程序和应用程序 

  对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
  服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。

  应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

  WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦

  常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

1.wsgiref 模块

  利用wsgiref模块来替换我们自己写的web框架的socket server部分

# 未拆分前代码
# http://127.0.0.1/index访问对应的名称到对应的页面
from wsgiref.simple_server import make_server

def index():
    return 'index'

def reg():
    return 'res'

def login():
    return 'login'

def error():
    return '404'

urls = [
    ('/index',index),
    ('/reg',reg),
    ('/login',login),
]

def run(env,reponse):
    reponse('200 OK', [])  # 固定格式
    print(env)  # 将http格式的数据处理完毕,形成一个字段给你调用
    current_path = env.get('PATH_INFO')
    # if current_path == '/index':
    #     return [b'index']
    func = None
    for url_tuple in urls:
        if current_path == url_tuple[0]:
            func = url_tuple[1]   # 如果路由匹配上了,就回去对应的函数
            break
    if func:
        res = func()
    else:
        res = error()
    return [res.encode('utf-8')]

if __name__ == '__main__':
    server = make_server('127.0.0.1',8080,run)  # 一直监听地址,只要有请求,就会给最后的函数或对象调用:run()执行
    server.serve_forever()
# urls.py 存放访问链接后的页面

from views import *
urls = [
    ('/index',index),
    ('/reg',reg),
    ('/login',login),
]


# views.py 存放访问页面函数
def index():
    return 'index'

def reg():
    return 'res'

def login():
    return 'login'

def error():
    return '404'

# wsgiref.py存放启动
from wsgiref.simple_server import make_server
from urls import urls
from views import *

def run(env,response):
    response('200 OK', [])  # 固定格式 不需掌握
    print(env)  # 将http格式的数据处理完毕 形成一个字段给你调用
    current_path = env.get('PATH_INFO')
    func = None
    for url_tuple in urls:
        if current_path == url_tuple[0]:
            func = url_tuple[1]  # 如果路由匹配上了 就回去对应的函数
            break
    if func:
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]

if __name__ == '__main__':
    server = make_server('127.0.0.1',8080,run)
    server.serve_forever()
拆分后代码

根据拆分后的代码,如果需要再添加访问页面,只需要在urls.py(路由与视图函数的映射关系)和views.py(视图函数)中增加对应的链接和函数就可以

2.动静态页面

  静态网页:数据是写死的,一直不变

  动态网页:数据实时获取的,一直在改变(eg:数据库的数据或当前时间)

2.1获取时间并显示在页面上:

# 在上面拆分代码的基础上
# urls.py增加
urls = [
    ('/index',index),
    ('/reg',reg),
    ('/login',login),
    ('/get_time',get_time),
]

# 对象视图views.py里增加函数
import time
def get_time():
    with open('templates/show_time.html','r',encoding='utf-8') as f:
        data = f.read()
    current_time = time.strftime('%Y-%m-%d %X')
    res = data.replace('timekkk',current_time)  # 字符串替换
    return res

然后运行wsgiref.py就可以看到页面上显示动态的时间了,每次刷新时间都会变化

2.2 给前端传字典并且字典可以取值

# urls.py中新增对应访问路径
from view2 import *

urls2 = [
    ('/index', index),
    ('/reg', reg),
    ('/login', login),
    ('/get_time', get_time),
    ('/get_user', get_user),
]

# views.py中新增对应函数
from jinja2 import Template

def get_user(env):
    user_dict = {'username': 'simon', 'password': '123'}
    with open('templates/get_user.html', 'r', encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)  # 实例化产生对象
    res = tmp.render(data=user_dict)  # 将user_dict传递给前端页面,前端页面用过变量名data就能够拿到user_dict字典
    return res

# html页面body中设置
{#传data这里就写data#}
{{ data }}
{#获取账号密码#}
<p>{{data.username}}</p>
<p>{{data['password']}}</p>
<p>{{data.hobby.0}}</p>
<p>{{data.hobby.1}}</p>

模板渲染(雏形)

  后端产生的数据直接传递给前端页面,前端页面获取数据通过模板语法展示

模板语法:

  {{}} 获取后端传递的数据,通过变量名(变量名相关的)

  {%%} 与逻辑相关的使用这个语法

  jinja2模板语法极为接近后端python语法

{{ data }}
<p>{{data.username}}</p>
<p>{{data['password']}}</p>
<p>{{data.hobby.0}}</p>
<p>{{data.hobby.1}}</p>
 

逻辑相关:

{%for user_dict in user_list%}
<tr>
<td>{{user_dict.id}}</td>
<td>{{user_dict.username}}</td>
<td>{{user_dict.password}}</td>
</tr>
{%endfor%}

2.3 数据库取值页面显示

#urls2.py
from view2 import *

urls2 = [
    ('/get_data',get_data),
]

# view2.py 新增函数
from jinja2 import Template
import pymysql

def get_data(env):
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '123',
        database = 'test',
        charset = 'utf8',
        autocommit = True
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    cursor.execute('select * from userinfo')
    res = cursor.fetchall()
    with open('templates/get_data.html','r',encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    res1 = tmp.render(user_list = res)
    return res1

# simple_server.py模块,和之前的没什么变化
from wsgiref.simple_server import make_server
from urls2 import urls2
from view2 import *

def run(env,reponse):
    reponse('200 OK', [])  # 固定格式
    print(env)  # 将http格式的数据处理完毕,形成一个字段给你调用
    current_path = env.get('PATH_INFO')
    # if current_path == '/index':
    #     return [b'index']
    func = None
    for url_tuple in urls2:
        if current_path == url_tuple[0]:
            func = url_tuple[1]   # 如果路由匹配上了,就回去对应的函数
            break
    if func:
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]

if __name__ == '__main__':
    server = make_server('127.0.0.1',8080,run)  # 一直监听地址,只要有请求,就会给最后的函数或对象调用:run()执行
    server.serve_forever()

# get_data.html前端页面代码
# body内容
<table>
    <thead>
        <tr>
            <th>id</th>
            <th>username</th>
            <th>password</th>
        </tr>
    </thead>
    <tbody>
        {%for user_dict in user_list%}
            <tr>
                <td>{{user_dict.id}}</td>
                <td>{{user_dict.username}}</td>
                <td>{{user_dict.password}}</td>
            </tr>
        {%endfor%}
    </tbody>
</table>
数据库取值

2.4 web服务渲染流程

  根据早上的流程,我们可以划出下面这个图

2.5 web框架

python主流三大框架:

   a.socket服务

   b:路由与视图函数映射关系

   c:模板渲染
  django:大而全 类似航空母舰

     a.用的别人的 wsgiref 上线之后会换成uwsgi;默认并发1000多,自己可以加nginx之类处理

     b.自己写的

     c.自己写的
  flask:小而精,轻量级框架

  a用的别人的  werkzeug  
  b自己写的
  c用的别人 jinja2
  tornado:异步非阻塞

    三者都是自己写的

三、Django简介

1.Django安装与注意事项

# 主意事项
    1.计算机名称不能含有中文
    2.一个pycharm窗口就是一个工程(项目)
    3.项目文件夹不要有中文

# ps:django版本: django 1.X(现在用的版本是这个1.11.11)

# 安装
    pip3 install django
# 或pycharm直接安装,可以指定版本specify version
# 如果已经安装了高版本需要降低版本:pip3 uninstall django,然后重新指定安装:pip3 install django ===1.11.20 或pycharm指定版本安装 # 查看djiango是否安装成功 命令行界面:django-admin # 命令行创建django项目 django-admin startproject 项目名 ps:创建一个应用面的文件夹,里面有一个跟应用名同名的文件夹和一个manage.py的文件 # 命令行创建应用 django-admin startapp 应用名 # application 一个django项目 可以有多个应用,django是一款开发应用的web框架 django项目就类似是一所大学,而里面的应用就类似于一个个学院 # 命令行启动项目 python manage.py runserver 启动成功后浏览器可以访问:http://127.0.0.1:8000和http://127.0.0.1:8000/admin ps:命令行创建django项目不会自动新建templates文件夹,并且settings.py配置文件(TEMPLATES 列表中DIRS)不会自动写templates文件夹路径,所以都需要手动添加[os.path.join(BASE_DIR,'templates')]
如下图:
# pycharm创建 项目:File-->New Project-->Django-->Location(创建项目)-->More Settings创建应用--->Application name:应用名 在pycharm的命令行中创建应用:Tools-->Run manage.py TASK-->startapp 应用名 应用创建后需要再settings.py中注册应用INSTALLED_APPS里添加 启动后可以访问:http://127.0.0.1:8000 # 注意: 1 在django中创建的应用必须去settings文件中注册才能生效,否则django不识别 2 确保不要端口冲突

2.Django项目目录结构

项目名
    应用名文件夹
        migrations文件夹
            数据库迁移记录
        admin.py
            django admin后台管理相关
        models.py
            模型类
        views.py
            视图函数
        
    项目同名文件夹
        settings.py
            django暴露给用户可配置的配置文件
        urls.py
            路由与视图函数映射关系
    templates
        所有的html文件
    manage.py
        django入口文件

3.Django 必会三板斧

# django小白必会三板斧

# HttpResponse:返回字符串
# views.py
def index(request):
    return HttpResponse("Hello Django index")
    
# render:返回html页面
def login(request):
    return render(request,'login.html')
    
# redirect:重定向
def home(request):
    return redirect('https://www.baidu.com')

# urls.py配置文件中加对应访问路径
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('login/', views.login),
    path('home/', views.home),
]

4.静态文件配置

# 动态实时监测到前缀的变化
login.html
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script>
    {% load static %}
    <link href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="stylesheet">
    <script src={% static "bootstrap-3.3.7/js/bootstrap.min.js" %}></script>
    
</head>

#用上述方法settings.py中接口前缀随便修改,也不需要修改html中的对应前缀

# settings.py
# 接口前缀:要想访问静态资源必须static打头:
#     <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
STATIC_URL = '/static/'
# 新增文件放置路径
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static'),
    os.path.join(BASE_DIR,'static1'),
    os.path.join(BASE_DIR,'static2'),
]

例:登录功能简单实现

# form表单默认是get请求
    get请求携带的参数是拼接在url后面的以?开头&链接,默认method方式为Get
    ps:get请求可以携带参数 但是参数的大小有限制 最大4KB,并且是明文的
    http://127.0.0.1:8000/login/?username=simon&password=123

# 如果改为method改为post提交,需要将settings.py中一行注释,否则会报403错误:
# 'django.middleware.csrf.CsrfViewMiddleware', # 跨站请求伪造

获取用户输入的框 都必须要有name属性

action参数有三种写法
    1.什么都不写 默认往当前页面的url地址提交
    2.只写路由后缀(******)
    <form action="/login/" method="post">
    3.写全路径
        <form action="https://www.baidu.com" method="post"> 
# 数据后端获取

#前端
            <form action="" method="post">
                <p>username:<input type="text" class="form-control" name="username"></p>
                <p>password:<input type="password" class="form-control" name="password"></p>
                <p>篮球<input type="checkbox" name="xxx" value="basketball"></p>
                <p>足球<input type="checkbox" name="xxx" value="football"></p>
                <p>冰球<input type="checkbox" name="xxx" value="ice"></p>
                <input type="submit" class="btn btn-success pull-right">
            </form>
# views.py:获取访问login页面的method以及post提交的数据
def login(request):
    print(request.method) # 获取当前请求方式
    if request.method == 'POST':
        # 获取post请求提交的数据
        print(request.POST)
        # get请求默认拿列表最后一个值:如-获取到2个username,取值永远拿最后一个元素
        username = request.POST.get('username')
        password = request.POST.get('password')  # 还可以在后面增加判断账号密码判断,以后通过数据库来判断传递的账号密码
     if username == "simon" and password == "123":
      return redirect("http://www.xiaohuar.com")
     return "xxxxxxx" hobby
= request.POST.getlist('xxx') print(hobby,type(hobby)) print(username,type(username)) print(password, type(password)) return render(request,'login.html') # 结果: POST <QueryDict: {'username': ['simon'], 'password': ['123'], 'xxx': ['basketball', 'football', 'ice']}> ['basketball', 'football', 'ice'] <class 'list'> simon <class 'str'> 123 <class 'str'>
原文地址:https://www.cnblogs.com/yangmeichong/p/11303746.html