本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名原文链接~~~

Django(1)之理解Web应用并创建第一个Django程序

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:


理解 Web 应用

我们可以这样理解:所有的 Web 应用本质上就是一个 Socket 服务端,而用户的浏览器就是一个 Socket 客户端。
浏览器在地址栏回车时会帮我们把 URL 封装到 HTTP 协议的报文中,然后请求到 URL 对应的服务端,服务端按照 HTTP 协议来响应请求,浏览器接收到 HTTP 响应后就会按照相应的规则将报文中响应体的部分渲染到浏览器,这部分通常是 HTML 格式的文本内容。

Socket 响应 Web 请求

响应字符串

下面就使用 Socket 完成一个最基本的基于 HTTP 协议的服务端。

import socket

# 创建 Socket 对象
server = socket.socket()
# 绑定到本机回环地址的 8080 端口
server.bind(('127.0.0.1', 8080))
# 允许监听
server.listen()
# 阻塞等待连接请求的到来
conn, addr = server.accept()
# 接收来自浏览器的请求信息
browser_msg = conn.recv(1024)
# 解码字节流为字符串
msg = browser_msg.decode('utf8')
print(msg)
conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
conn.send(b'hello')

conn.close()
server.close()

运行上面程序,浏览器请求 127.0.0.1:8080,会发现 hello 已经显示在浏览器上:

image.png

并且控制台输出了浏览器的请求报文如下:

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 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 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,en;q=0.8,en-US;q=0.7,en-GB;q=0.6,en-IN;q=0.5,en-NZ;q=0.4,en-ZA;q=0.3,en-CA;q=0.2,en-AU;q=0.1

响应 HTML

上个版本中,我们是直接返回给浏览器一个普通的字符串,而浏览器是支持解析 HTML 的,如果我们有一个 HTML 文件,该如何响应给浏览器呢?
在脚本统计目录创建一个 index.html 文件内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
<h1>hello</h1>
</body>
</html>

修改脚本如下:

import socket

# 创建 Socket 对象
server = socket.socket()
# 绑定到本机回环地址的 8080 端口
server.bind(('127.0.0.1', 8080))
# 允许监听
server.listen()
# 阻塞等待连接请求的到来
conn, addr = server.accept()
# 接收来自浏览器的请求信息
browser_msg = conn.recv(1024)
# 解码字节流为字符串
msg = browser_msg.decode('utf8')
conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
# 读取 html 文件内容
with open('index.html','rb') as html_file:
    conn.send(html_file.read())

conn.close()
server.close()

运行该脚本,浏览器请求 127.0.0.1:8080,浏览器显示如下:

image.png

响应图片

在上一个示例中查看浏览器的请求:

image.png

可以看到在浏览器地址栏敲上 127.0.0.1:8080 回车后浏览器实际上是发送了两个请求,一个就是以地址栏为目标地址的请求,另一个则是请求当前页面的图标,地址为 127.0.0.1:8080/favicon.ico,下面来响应一下这个图标。
在脚本同级目录下放上如下名为 favicon.jpg 的图片作为图标:

image.png

修改脚本如下:

import socket

# 创建 Socket 对象
server = socket.socket()
# 绑定到本机回环地址的 8080 端口
server.bind(('127.0.0.1', 8080))
# 允许监听
server.listen()

while 1:
    # 阻塞等待连接请求的到来
    conn, addr = server.accept()
    # 接收来自浏览器的请求信息
    browser_msg = conn.recv(1024)
    # 解码字节流为字符串
    msg = browser_msg.decode('utf8')
    print(msg)
    conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
    if 'favicon.ico' in msg:
        # 读取图片文件
        with open('favicon.jpg','rb') as jpg_file:
            conn.send(jpg_file.read())
    else:
        # 读取 html 文件内容
        with open('index.html','rb') as html_file:
            conn.send(html_file.read())

浏览器请求 127.0.0.1:8080,可以看到图标已经显示在标签栏:

image.png

wsgiref 实现的 Web 应用

上面是我们自己编写原生的 Socket 代码来完成对 HTTP 请求的响应,而类似这种功能已经有很多成熟的模块或框架帮我们做了,wsgiref 就是其中之一,下面使用 wsgiref 模块完成上面响应 Web 请求的功能:

from wsgiref.simple_server import make_server


def index():
    with open('index.html', 'rb') as html_file:
        html_bytes = html_file.read()
    return html_bytes


def favicon():
    with open('favicon.jpg', 'rb') as jpg_file:
        jpg_bytes = jpg_file.read()
    return jpg_bytes


def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    response = ''
    if url == '/':
        response = index()
    elif url == '/favicon.ico':
        response = favicon()
    return [response, ]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8080, run_server)
    print("我在8080等你哦...")
    httpd.serve_forever()

使用 Jinjia2 返回动态页面

1、安装:

$ pip3 install jinjia2

2、主程序代码如下:

from wsgiref.simple_server import make_server
from jinja2 import Template


def users():
    with open("user_template.html", "r", encoding="utf-8") as f:
        data = f.read()
    template = Template(data)  # 生成模板文件
    # 从数据库中取数据
    import pymysql

    conn = pymysql.connect(
        host="127.0.0.1",
        port=3306,
        user="root",
        password="root",
        database="testdb",
        charset="utf8",
    )
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("SELECT * FROM UserInfo;")
    user_list = cursor.fetchall()
    print(user_list)
    # 实现字符串的替换
    ret = template.render({"user_list": user_list})  # 把数据填充到模板里面
    return [bytes(ret, encoding="utf8"), ]


def index():
    with open("index.html", "rb") as f:
        data = f.read()
    return [data, ]


# 定义一个url和函数的对应关系
URL_LIST = [
    ("/index", index),
    ("/users", users),
]


def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    func = None  # 将要执行的函数
    for i in URL_LIST:
        if i[0] == url:
            func = i[1]  # 去之前定义好的url列表里找url应该执行的函数
            break
    if func:  # 如果能找到要执行的函数
        return func()  # 返回函数的执行结果
    else:
        return [bytes("404没有该页面", encoding="utf8"), ]


if __name__ == '__main__':
    httpd = make_server('', 8080, run_server)
    print("Serving HTTP on port 8080...")
    httpd.serve_forever()

3、在脚本统计目录新建模板文件 user_template.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>

<table border="1">
    <thead>
    <tr>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
    </tr>
    </thead>
    <tbody>
    {% for user in user_list %}
    <tr>
        <td>{{user.Name}}</td>
        <td>{{user.AGE}}</td>
        <td>{{user.SEX}}</td>
    </tr>
    {% endfor %}
    </tbody>
</table>
</body>
</html>

4、UserInfo 表数据如下:

image.png

5、启动主程序,浏览器访问 127.0.0.1:8080/users,结果如下:

image.png

MVC 和 MTV 框架

MVC

MVC 是 Web 服务器开发领域里著名的开发模式,所谓 MVC 就是把 Web 应用分为模型(Model),控制器(Controller)和视图(View)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:

image.png

MTV

MTV 模式被 Django 所使用,其本质和 MVC 是一样的,也是为了各组件间保持松耦合的关系,知识定义上有些许不同,Django 的 MTV 分别代表的是:

  • M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。
  • T 代表模板(Template):负责如何把页面(HTML)展示给用户。
  • V 代表视图(View):负责业务逻辑,并在适当时候调用 Model 和 Template。

除了以上三层之外,还需要一个 URL 分发器,它的作用是将一个个 URL 的对应的页面请求分发给不同的 View 处理,View 再调用相应的 Model 和 Template,MTV 的响应模式如下所示:

image.png

一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求会访问视图函数,视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户(如果不涉及到数据调用,那么这个时候视图函数直接返回一个模板也就是一个网页给用户)。

Django 的介绍与使用

Django 官网:djangoproject.com

Django 是 BSD 许可下的、开放源代码的项目,建议使用最新版本的 Python3。支持 Python 2.7 的版本是 Django 1.11 LTS。

支持的版本

Django 大概每 8 个月发布一次,这些版本将包含新功能和对现有功能的改进。

image.png

Hello Django

安装

1、直接在终端下执行下面命令进行下载安装:

$ pip3 install django==1.11.9

==1.11.9 表示安装指定的 1.11.9 版本,如果不指定则默认安装最新版本。

创建工程

2、创建一个 Django 工程,以创建一个名为 mysite 的工程为例,在指定目录下执行如下命令:

$ django-admin startproject mysite

执行完成后会在目录下生成 mysite 文件夹,目录结构如下:

mysite/
├── manage.py
└── mysite
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

其中各文件功用如下:

  • manage.py:通过它可以调用 Django shell 和数据库,启动关闭项目与项目交互等;
  • settings.py:包含了项目的默认设置,包括数据库信息,调试标志以及其它的一些工作变量;
  • urls.py:负责把 URL 请求映射到应用程序中的代码块;
  • wsgi.py:所有与 Socket 相关的内容都是从这个文件开始;

启动并测试访问

3、进入 mysite 目录执行下面命令启动 Django 项目:

$ python3 manage.py runserver 127.0.0.1:8000
Performing system checks...

System check identified no issues (0 silenced).

February 13, 2020 - 09:19:31
Django version 1.11.9, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

4、浏览器访问:

image.png

创建并配置应用

5、在 manage.py 所在目录执行以下命令来创建应用:

$ python3 manage.py startapp app1

其中 app1 是应用名称,一个 Django 工程中可有多个应用。
命令执行完毕后会在 manage.py 的同级目录下创建一个以应用名称命名的文件夹,在这里就是 app1 文件夹,其目录结构如下:

app1
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

这里我们只需要关注这两个文件:

  • models.py:存放与 app 相关的表结构;
  • views.py:存放与 app 相关的视图函数;

6、如果要使用新创建的应用需要修改 mysite 目录下的 settings 文件,在 INSTALLED_APPS 字段下添加上创建的应用名称,如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app1' # 此行是我们创建的应用
]

配置路由

7、修改 urls.py 文件如下:

from django.conf.urls import url
from django.contrib import admin

from app1 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^hello/', views.hello)
]

在其中导入新创建应用的 views 模块,并配置路由 /hello/ 映射到 views 模块的 hello 方法,路由格式支持正则。

编写视图

8、在 app1.views 文件中添加如下代码:

def hello(request):
    from django.shortcuts import HttpResponse
    return HttpResponse('Hello Django~~~')

启动并测试访问

9、重启项目,访问 127.0.0.1:8000/hello/,响应如下:

image.png

至此,基于 Django 的第一个 Web 工程就搭建完成。

# Django  

如果这篇文章对您有帮助,可点击下方链接分享给你的朋友们😋,如果遇到问题欢迎评论、留言~~~😇

评论

公众号:zze_coding

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×