Django实现算法web服务

1. django简介

Django是一个开放源代码的Web应用框架,由Python写成。其采用了MVC的软件设计模式,即模型(Model)、模板(Template)和视图(Views),因此也被称为 MTV 框架 。在 MTV 开发模式中:
M 代表模型,即数据存取层。该层处理与数据相关的所有事务,如何存取、如何确认有效性、包含哪些行为以及数据之间的关系等。
T 代表模板,即表现层。该层处理与表现相关的决定,如何在页面或其他类型文档中进行显示。
V代表视图,即业务逻辑层。这一层包含访问模型的逻辑和按照模板显示,可以认为它是模型和模板的桥梁。

2. 安装

pip install django

3. 创建项目流程

3.1 创建一个Django项目,名称为faceident

python django-admin.py startproject faceident

3.2 创建APP
      一个项目中包含一个或多个APP。APP可以理解为一块功能集合。每个Django APP都有独立的models,views等,具有易移植和可复用特性。
      注意:app的名称不能和项目名称faceident一样

cd faceident
python manage.py startapp app

3.3 目录文件说明
(1)子目录faceident下表示工程的全局配置,分别为setttings.py、urls.py和wsgi.py,其中setttings.py包括系统的数据库配置、应用配置和其他配置,urls.py则表示web工程Url映射的配置。
(2)子目录app则是在该工程下创建的APP,包含了models.py、tests.py和views.py等文件;其下新建的templates目录则为模板文件的目录,用来存放web界面模板html文件
(3)manage.py是Django提供的一个管理工具,可以同步数据库、运行项目等等


3.4 逻辑和页面分离
      在模板templates目录下创建一个index.html文件,规定web界面格式及算法结果返回显示,为算法与外部数据流的传输定义文件

<!DOCTYPE html>
<html>

<head>
    <title>身份识别平台</title>
    <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>

    <script type="text/javascript">
        function ProcessFile(e) {
            var file = document.getElementById('file').files[0];
            if (file) {
                var reader = new FileReader();
                reader.onload = function (event) {
                    var txt = event.target.result;

                    var img = document.createElement("img");
                    img.src = txt; //将图片base64字符串赋值给img的src
                    document.getElementById("result").appendChild(img);
                };
            }
            reader.readAsDataURL(file);
        }
        function contentLoaded() {
            document.getElementById('file').addEventListener('change',
                ProcessFile, false);
        }
        window.addEventListener("DOMContentLoaded", contentLoaded, false);
    </script>
</head>

<body>
<h1>信息输入</h1>
    <form action="/upload/" method="POST" enctype="multipart/form-data">
        编号:<input type="text" name="pig_id" id="pigNumber"/>
        <br>
        图片上传时间:<input type="date" name="upload_time" id="uploadTime"/>
        <br>
        猪场ID:<input type="text" name="location" id="location"/>
        <br>
            左侧脸:
        <br>
            请选取一个图像文件: <input type="file" id="ltfFile" name="ltf_img" />
        <br>
            正脸:
        <br>
            请选取一个图像文件: <input type="file" id="flfFile" name="flf_img" />
        <br>
            右侧脸:
        <br>
            请选取一个图像文件: <input type="file" id="rtfFile" name="rtf_img" />
        <br>
            <div id="result"></div>

            <div id="result_new"></div>

            <img id="ewmtp" src="https://img-blog.csdnimg.cn/2022010611283655454.png" alt="Red dot" />
        <br>
            <button type="button" class="btn btn-primary btn-lg" id="lgbut_compute">提交</button>
            <br>
        <div id="result1"></div>
        <div id="result2"></div>
    </form>
    <script>
        function ShowResult(data) {
            // var v = data['img64']; // data.img64
            // alert(v)
            // var obj = JSON.parse(data)
            var obj = data
            if (obj.identify_return){
                document.getElementById('result1').innerHTML = '输出信息:'
                document.getElementById('result2').innerHTML = obj.identify_return
            }
            else if (obj.error_value){
                alert(obj.error_value)
            }
        }
    </script>
    <script>
        $('#lgbut_compute').click(function () {
            var formdata = new FormData();
            var ltfFile = $("#ltfFile")[0].files[0];
            var flfFile = $("#flfFile")[0].files[0];
            var rtfFile = $("#rtfFile")[0].files[0];
            var pigNumber = $("#pigNumber").val();
            var uploadTime = $("#uploadTime").val();
            var location = $("#location").val();
            formdata.append("ltfFile", ltfFile, 'ltf');
            formdata.append("flfFile", flfFile, 'flf');
            formdata.append("rtfFile", rtfFile, 'rtf');
            formdata.append("pigNumber", pigNumber);
            formdata.append("uploadTime", uploadTime);
            formdata.append("location", location);
            $.ajax({
                url: '/identifyDemo/', //调用django服务器计算函数
                type: 'POST', //请求类型
                data: formdata,
                dataType: 'json', //期望获得的响应类型为json
                processData: false,
                contentType: false,
                success: ShowResult //在请求成功之后调用该回调函数输出结果
            })
        })
    </script>
</body>
</html>

3.5 创建数据表
(1)在models.py文件中,新建了一个FeatureDatabase类,继承自models.Model, 例如有猪只编号、猪场ID等属性。

from django.db import models

# Create your models here.
class FeatureDatabase(models.Model):    #index是Class的名称与views的相同,也是创建的表名
    id = models.CharField(verbose_name="编号", max_length=64, blank=True, null=False, primary_key=True)
    #upload_time = models.DateTimeField(verbose_name="添加时间", auto_now_add=True, blank=True, null=False)
    upload_time = models.CharField(verbose_name="添加时间", max_length=128, blank=True, null=False)
    location = models.CharField(verbose_name="ID", max_length=40, blank=True, null=False)
    flf_feature = models.CharField(verbose_name="正脸特征", max_length=1024, null=True)
    '''
    flf_img = models.ImageField(verbose_name="正脸图片", upload_to='img/%Y/%m/%d/', null=True)
    '''

(2)在setting.py文件中指定数据库(默认为sqlite3数据库,也可以替换为mysql数据库)

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
'''
'default': {
    'ENGINE': 'django.db.backends.mysql',   # 数据库引擎
    'NAME': 'FeatureDatabase',  # 数据库名,先前创建的
    'USER': 'root',     # 用户名,可以自己创建用户
    'PASSWORD': 'jsjsjxfd',  # 密码
    'HOST': '179.20.101.20',  # mysql服务所在的主机ip
    'PORT': '3306',         # mysql服务端口
}
'''
DATABASES = {
    'default': {
       'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

(3)先 cd 进入 manage.py 所在的那个文件夹下。
(4)输入下面的命令生成迁移文件migration,该文件是描述数据库结构变化的;需要注意这时候数据库还没真正变化,只是生成了描述数据库变化的文件。

python manage.py makemigrations

(5)将结构变化应用到数据库

python manage.py migrate

3.6 常见的数据库操作函数

(1)对数据进行查询

models.FeatureDatabase.objects.all()
models.FeatureDatabase.objects.all().values('user')    #只取user列
models.FeatureDatabase.objects.all().values_list('id','user')    #取出id和user列,并生成一个列表
models.FeatureDatabase.objects.get(id=1)
models.FeatureDatabase.objects.get(user='三毛')

(2)对数据进行增加

models.FeatureDatabase.objects.create(user='三毛',pwd='123456')
'''
dic = {'user':'三毛','pwd':'123456'}
models.FeatureDatabase.objects.create(**dic)
'''

(3)对数据进行删除

models.FeatureDatabase.objects.filter(user='三毛').delete()

(4)对数据进行更新

models.FeatureDatabase.objects.filter(user='三毛').update(pwd='23456')

'''
obj = models.FeatureDatabase.objects.get(user='三毛')
obj.pwd = '23456'
obj.save()
'''

3.7 响应函数views.py定义,用来定义数据交互、算法执行逻辑
      一般深度学习模型在使用过程中需要加载,每次发起post请求响应比较耗时较长(请求一次加载一次模型),可采用模型预加载的方式在django项目初次拉起时将模型加载在缓冲区(只加载一次)

from django.shortcuts import render

# Create your views here.
from django.shortcuts import HttpResponse
from django.views.decorators.csrf import csrf_exempt  # 跨站点验证
from django.http import JsonResponse   # json字符串返回
import json            # json字符串使用
import logging
from logging import handlers
import traceback
import os

from app.src.run import main

class Logger(object):
    level_relations = {
        'debug': logging.DEBUG,
        'info': logging.INFO,
        'warning': logging.WARNING,
        'error': logging.ERROR,
        'crit': logging.CRITICAL
    }

    def __init__(self, filename, level='info', when='D', backCount=7,
                 fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)
        format_str = logging.Formatter(fmt)
        self.logger.setLevel(self.level_relations.get(level))
        sh = logging.StreamHandler()
        sh.setFormatter(format_str)
        th = handlers.TimedRotatingFileHandler(filename=filename, when=when, backupCount=backCount,
                                               encoding='utf-8')
        th.setFormatter(format_str)
        self.logger.addHandler(sh)
        self.logger.addHandler(th)

op = Struct(**parms)
imgFaceRead = cv2.imread('init_data/init.jpg')
_, _ = op.single_process(image_array=imgFaceRead)

log_info = Logger('app/logs/info.log', level='info')
log_error = Logger('app/logs/error.log', level='error')
@csrf_exempt  # 用于规避跨站点请求攻击
def identifyDemo(request):

    if request.method == "POST":
        try:
            upload_dict = json.loads(request.body)
        except:
            log_info.logger.error('uploaded JSON data parse failed!')
            log_error.logger.error(traceback.format_exc())
            default = {"code": "100600203", "message": "uploaded JSON data parse failed"}
            return JsonResponse(default)
        '''
        results = main()
        default = {"code": "100000000",
                   "message": "Sucess",
                   "data": results}
        return JsonResponse(default)
        '''

    else:
        default = {"code": "100200400", "message": "unsafely executed"}  # 初始未执行
        log_info.logger.warning('post request failed!')
        return JsonResponse(default)

3.8 添加URL路由(用来定位项目执行函数i)
      在urls.py文件中,建立每个app的路由方式

(1)配置文件夹下主urls.py


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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app1/', include('app1.urls')),
    url(r'^app2/', include('app2.urls')),
    ]

(2)app目录下urls.py(自己新建)

from django.conf.urls import url
from app import views

urlpatterns = [
    url(r'^identifyDemo/$', views.identifyDemo, name='identifyDemo'),

]

3.9 在settings.py文件设置

(1)添加所有app,之后可通过“from app.文件名 import 函数名”的模式调用app里面定义好的函数(注意逗号)
       注意:DEBUG该项在实际使用中设为False

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app1',
    'app2',
]

(2)修改debug方式(调试True,上线False);修改hosts权限

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['*']

(3)修改时区为Asia/Shanghai(防止日志记录时间错误)

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Shanghai'#'UTC'

3.10 python脚本so封装
      Django认定的根目录为项目目录,经测试若把模型封装函数放在一个文件夹下(如frozen_models),通过“from frozen_models.函数封装文件名”方式无法定位到封装文件中的函数。解决方案有两种:
(1)若只有封装好的so文件,将其放在项目目录下即可
(2)若有源码文件,更改函数调用方式,使用from pigident.frozen_models.函数文件名,然后重新封装即可

import os
import re
import shutil
import argparse
try:
    from setuptools import setup, Extension
except ImportError:
    from distutils.core import setup
    from distutils.extension import Extension
from Cython.Build import cythonize

def get_file_list(pyfile_dir):
    files = os.listdir(pyfile_dir)
    file_list = []
    for file in files:
        if re.search('\.py$', file) and (re.match('main.py|soEncapsulation.py', file) is None):
            file_list.append(os.path.join(pyfile_dir, file))
        else:
            pass
    return file_list

def encapsulation(file_list, build_dir):
    build_tmp_dir = os.path.join(build_dir, 'tmp')
    setup(
        ext_modules=cythonize(file_list),
        script_args=["build_ext", "-b", build_dir, "-t", build_tmp_dir]
    )

def delete_c(pyfile_dir, build_dir):
    pyfiles = os.listdir(pyfile_dir)
    for pyfile in pyfiles:
        if re.search('\.c$', pyfile):
            os.remove(os.path.join(pyfile_dir, pyfile))
        else:
            pass
    print("All .c files had removed!")
    sofiles = os.listdir(build_dir)
    for sofile in sofiles:
        if re.match('^tmp$', sofile):
            shutil.rmtree(os.path.join(build_dir, sofile))
        elif re.search('\.so$', sofile):
            newfile = sofile.replace('.cpython-37m-x86_64-linux-gnu', '')
            os.rename(os.path.join(build_dir, sofile), os.path.join(build_dir, newfile))
        else:
            pass
    print("All .o files had removed!")

def parsers():

    parser = argparse.ArgumentParser(description='soEncapsulation, a tool to encapsulate .py to .so.')
    parser.add_argument('--pyfile_dir', help='dir with all .py files')
    parser.add_argument('--build_dir',help='dir to save .so and .o files')
    args = parser.parse_args()

    if not args.pyfile_dir:
        print('You must supply a pyfile_dir\n')
        parser.print_help()
        exit(0)

    if not args.build_dir:
        print('You must supply a build_dir\n')
        parser.print_help()
        exit(0)

    return args

if __name__ == "__main__":
    args = parsers()
    file_list = get_file_list(pyfile_dir=args.pyfile_dir)
    if not os.path.exists(args.build_dir):
        os.mkdir(args.build_dir)
    encapsulation(file_list=file_list, build_dir=args.build_dir)
    delete_c(pyfile_dir=args.pyfile_dir, build_dir=args.build_dir)

3.11 运行项目

调试模式:Python manage.py runserver IP:prot

生产模式:nginx+uwsgi+django

4. nginx+uwsgi生产环境上线django项目

     见https://blog.csdn.net/Mugo_Moon/article/details/115248388

 

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值