web框架前言

python学习网 2017-11-16 00:36:04

  对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

import socket

def f1(request):
    """
    处理用户请求,并返回相应的内容
    :param request: 用户请求的所有信息
    :return:
    """
    f = open('index.fsw','rb')
    data = f.read()
    f.close()
    return data
"""
<body>
    <h1>用户登录</h1>
    <form>
        <p><input type="text" placeholder="用户名" /></p>
        <p><input type="password" placeholder="密码" /></p>
    </form>
</body>
"""

def f2(request):
    f = open('aricle.tpl','rb')
    data = f.read()
    f.close()
    print(data)
    return data

"""
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th>1</th>
                <th>root</th>
                <th>root@qq.com</th>
            </tr>
        </tbody>
    </table>
</body>
"""

routers = [
    ('/xxx', f1),
    ('/ooo', f2),
]#手动写的网址


def run():
    sock = socket.socket()
    sock.bind(('127.0.0.1',8080))
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # hang住
        #print(conn)#获得的两个套接字,我去charm自己会发送请求一个/favicon.ico页面的报文
        # print(addr)
        # 有人来连接了
        # 获取用户发送的数据
        data = conn.recv(8096)
        data = str(data,encoding='utf-8')
        #print(data)#get报文
        headers,bodys = data.split('\r\n\r\n')
        #print("head:",headers)
        #print("body:",bodys) body是空的
        temp_list = headers.split('\r\n')
        # print(temp_list)
        method,url,protocal = temp_list[0].split(' ')
        # print(method)   GET
        # print(url)      /ooo  /favicon.ico
        # print(protocal)  /HTTP/1.1
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        func_name = None
        for item in routers:
            if item[0] == url:
                func_name = item[1]
                break

        if func_name:
            response = func_name(data)
            print(data)
        else:
            response = b"404"

        conn.send(response)
        conn.close()

if __name__ == '__main__':
    run()
静态网页

  这种静态页面不能与数据库连接交互,所以也是非常的low。

import socket

def f1(request):
    """
    处理用户请求,并返回相应的内容
    :param request: 用户请求的所有信息
    :return:
    """
    f = open('index.fsw','rb')
    data = f.read()
    f.close()
    return data
"""
<body>
    <h1>用户登录</h1>
    <form>
        <p><input type="text" placeholder="用户名" /></p>
        <p><input type="password" placeholder="密码" /></p>
    </form>
</body>
"""
def f2(request):
    f = open('aricle.tpl','r',encoding='utf-8')
    data = f.read()
    f.close()
    import time
    ctime = time.time()
    data = data.replace('@@sw@@',str(ctime))
    return bytes(data,encoding='utf-8')
"""
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <th>1</th>
                <th>@@sw@@</th>
                <th>root@qq.com</th>
            </tr>
        </tbody>
    </table>
</body>
"""
def f3(request):
    import pymysql

    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='jeff@123', db='db1')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id,username,password from userinfo")
    user_list = cursor.fetchall()
    #print(user_list)
    cursor.close()
    conn.close()

    content_list = []
    for row in user_list:
        tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row['id'],row['username'],row['password'])
        content_list.append(tp)
    content = "".join(content_list)


    f = open('userlist.html','r',encoding='utf-8')
    template = f.read()
    f.close()

    # 模板渲染(模板+数据)
    data = template.replace('@@sdfsdffd@@',content)
    return bytes(data,encoding='utf-8')
"""
mysql> select * from userinfo;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | alex     | 123      |
+----+----------+----------+
<body>
    <table border="1">
        <thead>
            <tr>
                <th>ID</th>
                <th>用户名</th>
                <th>邮箱</th>
            </tr>
        </thead>
        <tbody>
            @@sdfsdffd@@
        </tbody>
    </table>
</body>
"""
def f4(request):
    import pymysql

    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='jeff@123', db='db1')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id,username,password from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()

    f = open('hostlist.html','r',encoding='utf-8')
    data = f.read()
    f.close()

    # 基于第三方工具实现的模板渲染
    from jinja2 import Template
    template = Template(data)
    data = template.render(xxxxx=user_list,user='sdfsdfsdf')
    return data.encode('utf-8')
"""
            {% for row in xxxxx %}
                <tr>
                    <td>{{row.id}}</td>
                    <td>{{row.username}}</td>
                    <td>{{row.password}}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
    {{user}}

"""

routers = [
    ('/xxx', f1),
    ('/ooo', f2),
    ('/userlist.html', f3),
    ('/host.html', f4),
]


def run():
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1',8080))
    sock.listen(5)

    while True:
        conn,addr = sock.accept() # hang住
        # 有人来连接了
        # 获取用户发送的数据
        data = conn.recv(8096)
        data = str(data,encoding='utf-8')
        headers,bodys = data.split('\r\n\r\n')
        temp_list = headers.split('\r\n')
        method,url,protocal = temp_list[0].split(' ')
        conn.send(b"HTTP/1.1 200 OK\r\n\r\n")

        func_name = None
        for item in routers:
            if item[0] == url:
                func_name = item[1]
                break

        if func_name:
            response = func_name(data)
        else:
            response = b"404"

        conn.send(response)
        conn.close()

if __name__ == '__main__':
    run()
动态页面

  这里要说两点,首先这里使用了jinjia2模块,所以要简单的介绍一下这个模块。

  渲染模板(使用render_template方法)

@app.route('/about/')
def about():
  # return render_template('about.html',user='username')
  return render_template('about.html',**{'user':'username'})

  渲染模版时有两种传递参数的方式:用 var='value' 传递一个参数;使用字典组织多个参数,并且加两个*号转换成关键字参数传入。

  在jinja2模板中:

  {{ ... }}:装载一个变量,模板渲染的时候,会使用传进来的同名参数这个变量代表的值替换掉。

  {% ... %}:装载一个控制语句。

  {# ... #}:装载一个注释,模板渲染的时候会忽视这中间的值。

  变量:

  设置全局变量:{% set name='xx' %},之后就可以使用此变量了。

  设置局部变量:

{% with foo = 42 %}
{{ foo }}
{% endwith %}

  这里的foo变量只能在with标签中使用。

{% if kenny.sick %}
Kenny is sick.
{% elif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
if语句
#一般循环
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
#遍历字典
{% for key, value in my_dict.iteritems() %}
<dt>{{ key|e }}</dt>
<dd>{{ value|e }}</dd>
{% endfor %}
for循环

  jinja2模块最重要的部分是宏,宏相当于一个搭建好的页面一部分,可以被引入,可以往宏传递参数。可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量,在使用宏时传递参数,从而将宏渲染成为页面的一部分。

  更多关于此模块的操作,可以查看博客https://www.cnblogs.com/ygj0930/p/7170621.html。

  要说的第二点就是这种方法还是太low了。

import socket

def handle_request(client):

    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    client.send("<h1 style='color:red'>Hello, yuan</h1>".encode("utf8"))

def main():

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8001))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':

    main()
最low的socket服务端

  最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

  如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

  正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。

# from wsgiref.simple_server import make_server
#
#
# def application(environ, start_response):
#     start_response('200 OK', [('Content-Type', 'text/html')])
#     return [b'<h1>Hello, web!</h1><h2>Hello, py!</h2>']
#
#
# httpd = make_server('127.0.0.2', 8080, application)#(ip,pork,func)
#
# print('Serving HTTP on port 8080...')
# # 开始监听HTTP请求:
# httpd.serve_forever()
wsgiref模块

django入门

  django是一个基于python的高级web开发框架,因为他的高度集成,将会在今后的web开发里给予我们很大的帮助。

  首先创建一个django工程(加不加.py都可以):

django-admin.py startproject project_name
#django-admin.py startproject myblog

  工程下面有几个核心测文件:

  manage.py   Django项目里面的管理工具,通过它可以调用django shell和数据库等。

  settings.py    包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。

  urls.py    负责把URL模式映射到应用程序,路由(就是url与函数的对应关系)。

  wsgi.py    调用python内置的wsgiref模块,web服务网关接口。他定义django用什么socket实现,默认就是wsgiref模块。

  注:除了命令的方式pycharm也可以进行django工程的搭建。

  HttpResponse模块

from django.conf.urls import url
from django.shortcuts import HttpResponse

def index(request):#request用户请求相关的所有信息
    return HttpResponse('whatever')
urlpatterns = [
    url(r'^index/', index),
]

  启动django自带的服务器,

python manage.py runserver 8080

  在浏览器访问127.0.0.1:8080/index即可查看到django渲染后的网页。

  render模块

from django.conf.urls import url
from django.shortcuts import render

def index(request):#request用户请求相关的所有信息
    return render(request,"a.html")#默认要加request参数
urlpatterns = [
    url(r'^index/', index),
]

  接下来在浏览器访问127.0.0.1:8080/index即可查看到django渲染后的网页(服务器在改变了代码的情况下会自动重启)。还有,访问的前提是在templates目录下有一个a.html的文件。那么django是如何找到这个路径的呢,因为在settings.py下有一个TEMPLATES列表,其中'DIRS': [os.path.join(BASE_DIR, 'templates')]指明了render需要从这个目录下拿到。

  静态文件的配置

  在工程文件夹下创建一个static文件夹里面存放静态文件,并将路径写入settings.py下。

STATIC_URL = '/static/'
STATICFILES_DIRS=(os.path.join(BASE_DIR,'static'),)

  然后在导入文件时一律使用/static引入。

  request相关

  request.method获得当前请求的方法。request.GET与request.POST可以取到用户提交的数据。

from django.conf.urls import url
from django.shortcuts import render,redirect

def index(request):#request用户请求相关的所有信息
    if request.method =='GET':#浏览器默认传get,区分返回来的信息
        return render(request,"a.html")
    else:
        u=request.POST.get('user')#取出post方式传回来的字典的值
        p=request.POST.get('pwd')#get取不到会转化为none
        if u=='jeff' and p=='123':
            return redirect('http://www.baidu.com')#当然也可以重定向到自己的目录
        else:
            return render(request, "a.html")
urlpatterns = [
    url(r'^index/', index),
]

  a.html中的修改:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/as.css">
    <title>Title</title>
</head>
<body>
    <h1>用户登录</h1>
    <form method="post" action="/index/">{# 发送以post方式发到index下 #}
        <input type="text" name="user"/>
        <input type="password" name="pwd"/>
        <input type="submit" value="login"/>
    </form>
</body>
</html>

  这样用户访问127.0.0.1:8080/index会使用get方法返回a.html页面,输入用户名和密码提交会用post方法返回给index页面经判断是重定向还是重新输入。

  django的渲染模板

  django基本的html的模板与jinja2很相似,我们可以在form表单里加入一个{{ msg }}的模板,然后在render里添加一个msg:value用于自动传入。

  django的模板取序列的值也是简单粗暴,比如取列表就是{{  list.index }}例如{{ s.0 }}{{ s.1 }},字典就是{{ dict.key }}例如{{row.id}}{{ row.name }}。

from django.conf.urls import url
from django.contrib import admin
from django.shortcuts import HttpResponse,render,redirect

def index(request):#request用户请求相关的所有信息
    if request.method =='GET':
        return render(request,"a.html")
    else:
        u=request.POST.get('user')
        p=request.POST.get('pwd')
        print(u)
        print(p)
        if u=='jeff' and p=='123':
            return render(request, "b.html",{'user':[{'id':1,'name':'jeff','age':0},
                                                     {'id': 2, 'name': 'frank', 'age': 1},
                                                     {'id': 3, 'name': 'xixi', 'age': 2}]})
        else:
            return render(request, "a.html")
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', index),
]
urls.py配置
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/as.css">
    <title>Title</title>
</head>
<body>
    <h1>用户登录</h1>
    <form method="post" action="/index/">{# 发送以post方式发到index下 #}
        <input type="text" name="user"/>
        <input type="password" name="pwd"/>
        <input type="submit" value="login"/>
    </form>
</body>
</html>
a.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table border="1">
        {% for item in user %}
            <tr>
                <td>{{ item.id }}</td>
                <td>{{ item.name }}</td>
                <td>{{ item.age }}</td>
                <td><a href="/del/?nid=={{ item.id }}"></a></td>{# 跳转到专门的del页面 #}
            </tr>
        {% endfor %}{#循环结束 #}
    </table>
</body>
</html>
b.html

  这里render传入的字典可以使用pymsql导入,这样就与数据库紧密的连接到一起了。

阅读(814) 评论(0)