python 使用django库进行Web 开发(二)

导读:本篇文章讲解 python 使用django库进行Web 开发(二),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

推荐教程:
django Web 开发简介
Python Django 网站开发培训 – 2周入门 web后端开发 web服务端开发
django 简介|菜鸟教程

1 、前后端分离的架构

后端只负责提供和处理响应数据

<1> 代码直接生成HTML

from django.http import HttpResponse
# 导入 Customer 对象定义
from common.models import Customer

# 先定义好HTML模板
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>姓名</th>
        <th>电话号码</th>
        <th>地址</th>
        </tr>
        
        %s
        
        
        </table>
    </body>
</html>
'''

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 生成html模板中要插入的html片段内容
    tableContent = ''
    for customer in  qs:
        tableContent += '<tr>'

        for name,value in customer.items():
            tableContent += f'<td>{value}</td>'

        tableContent += '</tr>'

    return HttpResponse(html_template%tableContent)

在这里插入图片描述

<2> 使用模板

使用Django的模板引擎

from django.http import HttpResponse
# 导入 Customer 对象定义
from common.models import Customer

# 先定义好HTML模板
html_template = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>姓名</th>
        <th>电话号码</th>
        <th>地址</th>
        </tr>

        {% for customer in customers %}
            <tr>

            {% for name, value in customer.items %}            
                <td>{{ value }}</td>            
            {% endfor %}

            </tr>
        {% endfor %}

        </table>
    </body>
</html>
'''

from django.template import engines

django_engine = engines['django']
template = django_engine.from_string(html_template)


def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph = request.GET.get('phonenumber', None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 传入渲染模板需要的参数
    rendered = template.render({'customers': qs})

    return HttpResponse(rendered)

在这里插入图片描述

<3> 前后端分离架构

现在随着 浏览器中javascript 解释器性能的突飞猛进,以及一些前端模板库和框架的流行。很多架构师将 页面的html 内容生成 的任务放到前端。

这样 服务端就只负责提供数据, 界面的构成全部在前端(浏览器前端或者手机前端)进行,称之为前端渲染。

只是这个工作在前端执行, 使用前端的 框架库去完成,比如 Angular,React,Vue

这样 界面完全交给前端开发人员去做, 后端开发只需要提供前端界面所需要的数据就行了。

前端 和 后端 之间的交互就完全是 业务数据了。
这样需要 定义好 前端和后端 交互数据 的接口。

目前通常这样的接口设计最普遍的就是使用 REST 风格的 API 接口。

前端通过 API 接口 从后端获取数据展示在界面上。
前端通过 API 接口 告诉后端需要更新的数据是什么。

通常 前后端的 API 接口 是由 架构师 设计的, 有时也可以由经验丰富的前端开发者、或者后端开发者设计。

接下来我们就聚焦在后端,我们的系统前端由另外的团队开发,我们只负责后端业务数据的维护

现在我们的系统,API接口 已经由架构师定义好了,
点击这里查看 API接口

我们只需要根据这个接口文档,实现后端系统的部分。
注意:需要Django返回的信息,通常都是所谓的 动态 数据信息。 比如:用户信息,药品信息,订单信息,等等。

这些信息通常都是存在数据库中,这些信息是会随着系统的使用发生变化的。

而 静态 信息,比如: 页面HTML文档、css文档、图片、视频等,是不应该由 Django 负责返回数据的。

这些数据通常都是由其他的 静态资源服务软件,比如 Nginx、Varnish等等,返回给前端。这些软件都会有效的对静态数据进行缓存,大大提高服务效率。在实际的项目中,往往还会直接使用 静态文件 云服务( OSS + CDN )提供静态数据的访问服务。

总之,Django处理并返回的应该是动态业务数据信息。

2、对资源的增查改删处理

数据的管理,主要就是:响应前端的请求, 对数据资源的 增加、修改、删除、列出

<1> 创建 mgr应用目录

接口文档明确说明了,这是针对 管理员用户 的 请求。

前面我们已经为 销售员用户 专门创建了一个应用 sales 来处理相关的 请求。

所以,我们可以 再为 管理员用户 专门创建一个应用 mgr 来处理相关的 请求。 怎么创建还记得吗?

对了,执行

python manage.py startapp mgr

在这里插入图片描述

<2> 添加处理请求模块 和 url 路由

【1】编写分发路由的函数

编写分发路由的函数, 来根据 http请求的类型 和请求体里面的参数 分发(或者说路由)给 不同的函数进行处理。

mgr/customer.py 中定义如下 dispatcher 函数

def dispatcher(request):
    # 将请求参数统一放入request 的 params 属性中,方便后续处理

    # GET请求 参数在url中,同过request 对象的 GET属性获取
    if request.method == 'GET':
        request.params = request.GET

    # POST/PUT/DELETE 请求 参数 从 request 对象的 body 属性中获取
    elif request.method in ['POST','PUT','DELETE']:
        # 根据接口,POST/PUT/DELETE 请求的消息体都是 json格式
        request.params = json.loads(request.body)


    # 根据不同的action分派给不同的函数进行处理
    action = request.params['action']
    if action == 'list_customer':
        return listcustomers(request)
    elif action == 'add_customer':
        return addcustomer(request)
    elif action == 'modify_customer':
        return modifycustomer(request)
    elif action == 'del_customer':
        return deletecustomer(request)

    else:
        return JsonResponse({'ret': 1, 'msg': '不支持该类型http请求'})

【2】修改路由文件

接下来,根据 API 接口 ,我们发现 凡是 API 请求url为 /api/mgr/customers 的,都属于 客户 相关的API, 都应该交由 我们上面定义的dispatch函数进行分派处理。

那么我们需要在Django的url路由文件中加入对应的路由。

所以,
第一步:我们应该在 总路由文件 config/urls.py 中定义了如下部分

    # 凡是 url 以 api/mgr  开头的,
    # 都根据 mgr.urls 里面的 子路由表进行路由
    path('api/mgr/', include('mgr.urls')),

在这里插入图片描述

第二步: 在 mgr 目录下面添加mgr/urls.py 路由文件, 并 加入如下声明即可, 如下所示

from django.urls import path

from mgr import customer

urlpatterns = [

    path('customers', customer.dispatcher),
]

在这里插入图片描述

这样,就表示 凡是 API 请求url为/api/mgr/customers 的,都交由 我们上面定义的dispatch函数进行分派处理

<3> 对应接口文档编写函数操作客户数据

BYSMS系统 API 接口 1.0

【1】列出所有客户

请求消息

GET  /api/mgr/customers?action=list_customer  HTTP/1.1

请求参数
http 请求消息 url 中 需要携带如下参数,

  • action
    填写值为 list_customer

响应消息

HTTP/1.1 200 OK
Content-Type: application/json

响应内容
http 响应消息 body 中, 数据以json格式存储,

如果获取信息成功,返回如下

{
    "ret": 0,
    "retlist": [
        {
            "address": "江苏省常州武进市白云街44号",
            "id": 1,
            "name": "武进市 袁腾飞",
            "phonenumber": "13886666666"
        },
        
        {
            "address": "北京海淀区",
            "id": 4,
            "name": "北京海淀区代理 蔡国庆",
            "phonenumber": "13990123456"
        }
    ]              
}

函数
mgr/customer.py:

# 导入 Customer 
from common.models import Customer

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 将 QuerySet 对象 转化为 list 类型
    # 否则不能 被 转化为 JSON 字符串
    retlist = list(qs)

    return JsonResponse({'ret': 0, 'retlist': retlist})

在这里插入图片描述
可以发现,无需转化数据为HTML, 后端的代码任务也大大减轻。

【2】 添加一个客户

mgr/customer.py:

def addcustomer(request):

    info    = request.params['data']

    # 从请求消息中 获取要添加客户的信息
    # 并且插入到数据库中
    # 返回值 就是对应插入记录的对象 
    record = Customer.objects.create(name=info['name'] ,
                            phonenumber=info['phonenumber'] ,
                            address=info['address'])

【3】修改客户信息

根据接口文档,修改客户数据接口,前端提供的数据格式如下

{
    "action":"modify_customer",
    "id": 6,
    "newdata":{
        "name":"武汉市桥北医院",
        "phonenumber":"13345678888",
        "address":"武汉市桥北医院北路"
    }
}

mgr/customer.py:

def modifycustomer(request):

    # 从请求消息中 获取修改客户的信息
    # 找到该客户,并且进行修改操作
    
    customerid = request.params['id']
    newdata    = request.params['newdata']

    try:
        # 根据 id 从数据库中找到相应的客户记录
        customer = Customer.objects.get(id=customerid)
    except Customer.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id 为`{customerid}`的客户不存在'
        }


    if 'name' in  newdata:
        customer.name = newdata['name']
    if 'phonenumber' in  newdata:
        customer.phonenumber = newdata['phonenumber']
    if 'address' in  newdata:
        customer.address = newdata['address']

    # 注意,一定要执行save才能将修改信息保存到数据库
    customer.save()

    return JsonResponse({'ret': 0})

【4】删除客户

根据接口文档,删除客户数据接口,前端只需要提供要删除的客户的ID。

数据格式如下

{
    "action":"del_customer",
    "id": 6
}

我们可以使用如下的函数来处理
mgr/customer.py:

def deletecustomer(request):

    customerid = request.params['id']

    try:
        # 根据 id 从数据库中找到相应的客户记录
        customer = Customer.objects.get(id=customerid)
    except Customer.DoesNotExist:
        return  {
                'ret': 1,
                'msg': f'id 为`{customerid}`的客户不存在'
        }

    # delete 方法就将该记录从数据库中删除了
    customer.delete()

    return JsonResponse({'ret': 0})

【5】临时取消 CSRF 校验

根据接口文档,添加客户 请求是个Post请求

POST /网站名/api/mgr/signin  HTTP/1.1
Content-Type:   application/x-www-form-urlencoded

注意,缺省创建的项目, Django 会启用一个 CSRF (跨站请求伪造) 安全防护机制。

在这种情况下, 所有的Post、PUT 类型的 请求都必须在HTTP请求头中携带用于校验的数据。

为了简单起见,我们先临时取消掉CSRF的 校验机制,等以后有需要再打开。

要临时取消掉CSRF的 校验机制,非常简单,只需要在 项目的配置文件 config/settings.pyMIDDLEWARE 配置项 里 注释掉 django.middleware.csrf.CsrfViewMiddleware 即可。
在这里插入图片描述

<4> 与前端进行集成

最终终前端和后端系统会集成在一起成为一个完整的系统。

部署到生产环境(生产环境就是正式的线上运营环境)运行的架构往往比较复杂。

开发环境下, 前后端分离的架构如何简单集成。
前端环境其实就是 一些前端的代码和资源文件,包括 js文件、html文件、css文件 还有 图片视频文件等。

我们模拟前端团队开发的 前端 系统 打包在这里 ,点击这里下载

下载好以后,可以解压该 z_dist.zip 文件到项目根目录下面,形成一个目录 z_dist。

该目录下面就是前端的 代码资源文件。
在这里插入图片描述

Django的开发环境也可以从浏览器访问这些前端的资源文件。

但是前端文件都是静态文件,需要我们配置一下Django的配置文件, 指定http请求如果访问静态文件,Django在哪个目录下查找。

注意,接下来我们配置 Django 静态文件服务, 是 开发时 使用的 一种 临时方案 ,性能很低,这是方便我们调试程序用的

开发模式:
在这里插入图片描述前面讲过,正式部署web服务的时候,不应该这样干,应该采用其它方法,比如Nginx等。后面的教程会有详细的讲解如何使用Nginx 和 Django 组合使用。现在,请打开 config/urls.py 文件,在末尾 添加一个

from django.contrib import admin
from django.urls import path, include
# 静态文件服务
from django.conf.urls.static import static

# from sales.views import listorders
# python manage.py runserver 0.0.0.0:80
urlpatterns = [
    path('admin/', admin.site.urls),

    path('sales/', include('sales.urls')),

    path('api/mgr/', include('mgr.urls')),
    
] + static("/", document_root="./z_dist")

在url 路由中加入 前端静态文件的查找路径。
在这里插入图片描述
访问http://localhost/mgr/index.html
http://localhost/mgr/index.html#/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、处理登录、登出请求

<1> 处理登录、登出请求

我们可以在mgr目录里面创建一个代码文件 sign_in_out.py,用来处理管理员登录和登出 的API 请求的。

当我们执行 migrate 创建数据库表时,根据,就会为我们创建 用户表 auth_user,如下所示
在这里插入图片描述

django.contrib.auth 这个app 已经 为我们做好了登录验证功能。
我们只需要使用这个app库里面的方法就可以了。
Django的文档就给出了登录和登出代码范例,我们稍微修改一下。

mgr/sign_in_out.py

from django.http import JsonResponse

from django.contrib.auth import authenticate, login, logout


# 登录处理
def signin(request):
    # 从 HTTP POST 请求中获取用户名、密码参数
    userName = request.POST.get('username')
    passWord = request.POST.get('password')

    # 使用 Django auth 库里面的 方法校验用户名、密码
    user = authenticate(username=userName, password=passWord)

    # 如果能找到用户,并且密码正确
    if user is not None:
        if user.is_active:
            if user.is_superuser:
                login(request, user)
                # 在session中存入用户类型
                request.session['usertype'] = 'mgr'

                return JsonResponse({'ret': 0})
            else:
                return JsonResponse({'ret': 1, 'msg': '请使用管理员账户登录'})
        else:
            return JsonResponse({'ret': 0, 'msg': '用户已经被禁用'})

    # 否则就是用户名、密码有误
    else:
        return JsonResponse({'ret': 1, 'msg': '用户名或者密码错误'})


# 登出处理
def signout(request):
    # 使用登出方法
    logout(request)
    return JsonResponse({'ret': 0})

在这里插入图片描述

<2> 创建 url路由

系统中,浏览器登陆登录页面的url是 http://127.0.0.1/mgr/sign.html
但是这不是 登录 API接口的url路径。
根据接口,管理员登录的API 路径是 /api/mgr/signin
前面的课程, 我们已经在总路由文件config/urls.py中 添加了如下路由记录

# 凡是 url 以 api/mgr  开头的,
# 都根据 mgr.urls 里面的 子路由表进行路由
path('api/mgr/', include('mgr.urls')),

现在,我们只需要 在mgr 目录下面 的子路由文件 urls.py 里添加如下内容
mgr/urls.py

from mgr import customer
from django.urls import path
# 添加如下内容
from mgr import sign_in_out

urlpatterns = [
    path('customers', customer.dispatcher),

    # 添加如下内容
    path('signin', sign_in_out.signin),
    path('signout', sign_in_out.signout),
]

在这里插入图片描述
这样就表示:

如果有HTTP请求 url是/api/mgr/signin就由 sign_in_out.py 里面的signin 函数处理,

如果有HTTP请求 url是/api/mgr/signout 就由 sign_in_out.py 里面的signout 函数处理。

<3>测试

【1】代码测试:

密码错误:

import pprint
import requests

payload = {
    'username': 'admin',
    'password': '88888888'
}

response = requests.post('http://localhost/api/mgr/signin',
                         data=payload)

pprint.pprint(response.json())

在这里插入图片描述
密码正确:

payload = {
    'username': 'admin',
    'password': '123456'
}

在这里插入图片描述

【2】界面测试:

在这里插入图片描述
在这里插入图片描述
成功直接跳转

【3】apizza 测试

apizza:极客专属的接口协作管理工具
官网:https://www.apizza.net/
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92669.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!