内容


使用 Python、Django 和 MongoDB 在 Bluemix 上构建和部署一个基于 World Bank 数据的制图应用

Comments

World Bank 提供了对有关全球各个国家的发展指标的海量数据的免费和开放访问,这些指标涉及经济、健康、环境、能源、基础架构、贫困、社会发展、教育、科学和技术等领域。能够在曲线图和图表中可视化 World Bank 数据,帮助数据分析师理解当前某个国家在各个领域的发展水平的评估结果。

本文将介绍如何开发一个基于 Web 的制图应用程序,用该应用程序从 World Bank API 拉取数据,并以一种可理解的图表方式呈现这些数据。

对于开发人员,这带来了一个使用 World Bank 数据构建应用程序的机会,这些应用程序可以帮助政府采取相应的预防措施和纠正措施,使他们国家的资源可以得到最好的管理,从而实现快速发展。本文将介绍如何开发一个基于 Web 的制图应用程序,用该应用程序从 World Bank API 拉取数据,并以一种可理解的图表方式呈现这些数据。

为了便于编码和解释,我的制图应用程序主要显示各个国家的能源消耗趋势。能源消耗仪表板提供了各种能源来源的消耗趋势的快速洞察,比如不同国家的太阳能、生物燃料、水利、风和地热能源。

运行应用程序获取代码

关于该应用程序

该应用程序是在 IBM Bluemix 上使用 Python、Django 和 MongoDB(作为数据缓存)进行开发的。前端是使用 JavaScript 制图引擎 Highcharts 所公开的制图 API 来设计的。Highcharts 还支持用户打印图表,或者以图像或 PDF 格式下载它们。Django 是一个基于 Python 的开源 Web 应用程序框架,它鼓励快速开发 Web 应用程序,让用户能够编写干净、容易维护的代码。一些使用 Django 的著名站点包括 Pinterest、Instagram、Mozilla、The Washington Times、Disqus 和 Public Broadcasting Service。

任何时候在该应用程序中查询任何统计数据或指标(比如美国的太阳能消耗),都将从 World Bank REST API 抓取与该指标关联的 JSON 数据,并使用 PyMongo 会话将这些数据存储在 MongoDB 集合中。此数据将会在 MongoDB 中缓存一天。对于寻找相同统计数据的查询,可以从 MongoDB 缓存中拉取该数据来进行处理,无需查询 World Bank API。数据缓存每天刷新一次,并再次填入对应用程序的第一次调用的结果。

在本文的最后一部分中,我将介绍如何轻松地将该应用程序部署到 Bluemix ,Bluemix 是 IBM 用来构建、管理和运行应用程序和服务的开放标准、基于云的平台。

我们开始构建这个制图应用程序吧!

构建这个应用程序需要做的准备工作

如果想要将应用程序直接部署到 Bluemix,不想在本地进行开发,那么您可以跳过此处的第 1-3 步,直接执行 第 4 步将应用程序部署到 Bluemix。您可以使用以下命令从 IBM JazzHub 存储库克隆源代码:

git clone https://hub.jazz.net/git/mamtasharma/trendsapp001

也可以单击上面的获取代码按钮,使用 DevOps Services 在线浏览完整的代码。有关该代码的详细解释,请参见 第 3 步创建和配置本文的制图应用程序

第 1 步. 设置一个 Django 项目

  1. 安装 Python 和 Django。对于本地设置,确保您在安装 Django 之前已经安装了 Python。
  2. 创建一个 Django 项目。Django 中的项目是一个 Django 实例的设置集合,包括数据库配置、特定于 Django 的选项,以及特定于应用程序的设置。要创建一个 Django 项目,请运行以下命令:
    django-admin.py startproject trends_app

    startproject 命令创建一个名为 trends_app 的目录,其中包含 5 个文件。这些文件(已在下面列出)已构成一个能正常运行的 Django 应用程序。

    trends_app/
        manage.py
        trends_app/
            __init__.py
            settings.py
            urls.py
            wsgi.py
  3. 如果非常熟悉 Django,那么您可以跳过这些文件的以下细节。如果不熟悉 Django,以下简短描述应该可帮助您基本理解这些文件的用途。
    • trends_app/:外部的 trends_app/ 目录类似于 Django 项目的一个容器。
    • manage.py:这个命令行实用程序允许您与 Django 项目交互。键入 python manage.py 会得到一个可用命令列表。
    • trends_app/trends_app/:内部的 trends_app/trends_app 目录是您项目实际的 Python 包。它的名称是您导入其中的任何内容时需要使用的 Python 包名称,例如 import trends_app.settings
    • __init__.py:Python 需要这个文件来将 trends_app/ 目录当作一个包(一组 Python 模块)进行处理。
    • settings.py:这个 Django 项目的设置/配置。
    • urls.py:这个 Django 项目的 URL。可将此视为您受 Django 支持的站点的 “目录”。
    • wsgi.py:兼容 WSGI 的 Web 服务器处理您的项目的入口点。

第 2 步. 启动开发服务器

Django 有一个内置的轻量型开发 Web 服务器,它会在对源代码执行任何更改时自动重新加载。

  1. 要启动该服务器,可以更改到您项目的容器目录 (cd trends_app) 并运行此命令:
    python manage.py runserver

    如果看到以下消息,则意味着服务器已在本地的 8000 端口上启动。

    Validating models...
    
    0 errors found
    August 25, 2014 - 21:51:25
    Django version 1.6.5, using settings 'trends_app.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.
  2. 使用您的 Web 浏览器访问 http://127.0.0.1:8000/,您会看到您的第一个 Django 页面。 第一个受 django 支持的页面
    第一个受 django 支持的页面

第 3 步. 创建和配置这个制图应用程序

  1. 使用以下命令创建一个示例 Django 应用程序,这会创建一个名为 trends 的 Django 应用程序。
    django-admin.py startapp trends
  2. 修改 settings.py 文件以使用以下代码:
    INSTALLED_APPS = (
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'django.contrib.messages',
        trends,
    )
  3. 现在,配置 URL 映射。该映射规定了您如何访问您的应用程序。下面这个代码清单显示了 trends_app/urls.py 文件应有的内容:
    from django.conf.urls import include, url
    
    urlpatterns = [
        url(r'^trends/', include('trends.urls'))
    ]
  4. 更改 trends/urls.py 文件,使之包含将 URL fetch_and_draw_data/ 映射到 fetch_and_draw_data() 视图函数的代码,如下面这个代码清单所示。trends/urls.py 文件将一个 URL 映射到一个视图函数,以便 Django 知道在何处找到视图函数。
    urlpatterns = [
        url(r'^$', views.index, name='index'),
        url(r'^fetch_and_draw_data/', views.fetch_and_draw_data, name='fetch_and_draw_data'),
    ]
  5. 将下面这个名为 fetch_and_draw_data() 的视图函数包含在 trends/views.py 文件中。trends/views.py 文件包含接受一个请求参数并返回一个响应的 Python 函数。这里的请求通常是来自 Web 服务器的请求,视图会获取在此请求中传递的所有参数。然后,视图会执行必要的逻辑来确定合适的响应。
    def fetch_and_draw_data(request):
        connect.initialize()
        country = request.GET.get('country', 'USA')
        metric = request.GET.get('metric', 'Total')
    
        country_code = countries_mapping[country]
        indicator_code = indicators_mapping[metric]
        data_url = get_url(country_code, indicator_code)
        json_from_cache = connect.get_json_data(data_url)
        ...
        //create a data list
        data_list = {"graphTitle": graphTitle ,"xAxisLabels" : xAxisLabels,
        "xAxisTitle" : xAxisTitle, "yAxisTitle" : yAxisTitle, "yAxisValues" : yAxisValues}
        return HttpResponse(simplejson.dumps(data_list))
  6. 创建一个名为 trends/connect.py 的新文件并将 initialize() 函数添加到其中。trends/connect.py 文件负责建立与 MongoDB 的连接。该连接是使用 PyMongo 建立的(这是 MongoDB 的一个 Python 接口)并通过调用 initialize() 函数来在 MongoDB 中进行初始化。

    下面这段代码展示了如何使用从 Bluemix VCAP_SERVICE 变量获取的连接凭据建立一个 PyMongo 会话(假设您已有一个 MongoDB 服务实例在 Bluemix 上运行)。

    # Initialize MongoDB connection with credentials from vcap config
    def initialize():
      # If connection is not initialized, initialize it.
      if not config.initialized:
        #Get the connection credentials from VCAP variables
        vcap_config = os.environ.get('VCAP_SERVICES')
        decoded_config = json.loads(vcap_config)
        for key, value in decoded_config.iteritems():
             if key.startswith('mongodb'):
                 mongo_creds = decoded_config[key][0]['credentials']
        mongo_url = str(mongo_creds['url'])
    
        client = pymongo.MongoClient(mongo_url)
        config.db = config.client['db']
        config.collection = config.db['mycollection']
        config.collection.remove({})
        config.initialized=True
        refresh()
  7. refresh() 函数添加到 trends/connect.py 文件中。refresh() 函数会在执行 initialize() 函数时调用。这是一个定期任务,每隔 24 小时执行一次,并会清理 MongoDB 集合中的现有数据,以便对该应用程序的下一次调用会从 World Bank REST URL 抓取数据。
    # Periodic task to purge data from MongoDB collection
    def refresh():
      config.collection.remove({})
      threading.Timer(86400, refresh).start()
  8. get_url() 函数添加到 trends/views.py 文件中。get_url() 函数会获取国家代码和指标名称(例如太阳能消耗),使用它们作为请求参数,并构造一个 API URL,如以下代码清单所示:
    def get_url(country_code, indicators):
      return ("http://api.worldbank.org/countries/%s/indicators/%s?per_page=10&\
       date=2000:2010&format=json" % (country_code, indicators)) ;
  9. get_json_data() 函数添加到 trends/connect.py 文件中。这个函数会检查该 URL 是否已存在于 MongoDB 集合中。如果未找到针对该 URL 的条目,那么它会调用 API URL 来检索 JSON 格式的数据,然后将该数据缓存在 MongoDB 集合中。如果找到了该条目,那么它会返回与现有 URL 对应的缓存数据。

    下面这个代码清单显示了如何通过调用 get_json_data() 函数来抓取和缓存数据。

    # Hit the World Bank url to retrieve data
    def get_json_data(data_url):
      # If data is in cache, return it
      if(config.collection.find_one({"url": data_url}) is not None):
        return config.collection.find_one({"url": data_url})["jsonData"]
      # Fetch it from MongoDB otherwise
      else:
        response = urllib2.urlopen (data_url)
        jsonData = simplejson.load(response)
        config.collection.insert({'url': data_url, 'jsonData' : jsonData})
        return jsonData
  10. 在 trends_app 目录中添加一个名为 templates 的目录。然后,在 templates 目录中,添加一个名为 index.html 的文件(项目中惟一的模板),并将 Highcharts JS 库导入其中。Highcharts JS 是一个 JavaScript 制图引擎,以交互式图表形式呈现数据的灵活方法和简单方法使得 Highcharts JS 得以著名。

    下面这个代码清单显示了 Highcharts 导入代码:

     # Import highchart javascript
    <script src="//code.highcharts.com/highcharts.js"></script>
    <script src="//code.highcharts.com/modules/exporting.js"></script>
  11. 将 JavaScript fetch_and_draw() 函数添加到 index.html 文件中。这个函数对后端 fetch_and_draw_data 视图函数执行一次 Ajax 调用,如下面这个代码清单所示。
     $.ajax({
                    url : "/trends/fetch_and_draw_data",
                    type : "GET",
                    dataType: "json",
                    data : {
                        csrfmiddlewaretoken: '{{ csrf_token }}',
                        country : country,
                        metric : metric
                    },

    从选项卡菜单选择一个指标或从下拉菜单选择一个国家后,将会检索 tab_id 并调用 fetch_and_draw() 函数,该函数进而对 fetch_and_draw_data URL 执行一次 Ajax 调用,从后端获取数据。最后,使用 Highcharts 来呈现直方图。下面这段代码显示了对 JavaScript 函数 fetch_and_draw() 的调用:

    $('#tabs').tabs({
            activate: function(event ,ui){
              var tab_id = ($("#tabs").tabs('option', 'active'));
              tab_id += 1;
              fetch_and_draw(tab_id);
                
            }
        });
    
    
    $('#countries_id').change(function()
            {
              var tab_id = ($("#tabs").tabs('option', 'active'));
              tab_id += 1;
              fetch_and_draw(tab_id);
            
        });

    您可以在 JazzHub 上看到 views.py 和 index.html 文件的完整代码。

第 4 步. 将应用程序部署到 Bluemix

在编写应用程序代码后,是时候将它部署到 Bluemix 了。

  1. 将 requirement.txt 文件添加您项目的根目录下。requirement.txt 文件应包含运行该制图应用程序所需的所有外部依赖项(比如 Django 和 PyMongo)。运行应用程序时,Bluemix 会确保读取了此文件并安装了列出的依赖项。

    此项目需要的 requirement.txt 文件是:

    Django==1.6.5
    pymongo==2.7.1
  2. 在项目的根目录下创建 run.sh 文件。run.sh 文件是在该 Web 应用程序部署到 Bluemix 上之后启动它的 shell 脚本。在启动 Web 服务器时,请确保您从环境变量 VCAP_APP_PORT 中获得了端口值。

    将以下行添加到 run.sh 文件中。

    #!/bin/bash
    if [ -z "$VCAP_APP_PORT" ];
    then SERVER_PORT=5000;
    else SERVER_PORT="$VCAP_APP_PORT";
    fi
    echo port is $SERVER_PORT
    python manage.py runserver --noreload 0.0.0.0:$SERVER_PORT
  3. 下载并安装 Cloud Foundry (cf) 命令行工具,该工具将用于上传和管理应用程序。要验证 Cloud Foundry 是否已成功安装,可以运行以下命令来返回版本号:
    cf --version
  4. 登录到 Bluemix 并设置端点。可以运行以下命令来从 CLI 登录到 Bluemix:
    cf login -a https://api.ng.bluemix.net
  5. 将应用程序推送到 Bluemix。转到您项目的根目录 (trends_app/),并运行以下命令将制图应用程序上传到 Bluemix:
    cf push  trendsapp001 --no-manifest --no-start -b https://github.com/cloudfoundry/python-buildpack  
    -c "sh run.sh"

    --no-start 选项指示应用程序只有在绑定到需要的服务后才应启动。这可以确保在应用程序启动之前,MongoDB 服务已绑定到该应用程序。

    -c 选项用于指定在启动应用程序时 Bluemix 应执行的启动命令。

    -b 标志指示要使用的构件包。对于这个制图应用程序,我们需要一个 Python 运行时,可以通过使用 -b 选项向 Git 存储库传递 Python 构件包的 URL (https://github.com/cloudfoundry/python-buildpack) 来获取它。

    也可以在 manifest.yml 配置文件中提供应用程序名称、构件包信息和 sh run.sh 命令,如下所示:

    ---
    applications:
    - name: trendsapp001
      memory: 256M
      command: sh run.sh
      buildpack: https://github.com/cloudfoundry/python-buildpack
  6. 将 manifest.yml 文件包含在项目根中。在使用 manifest.yml 文件时,使用以下命令将该应用程序推送到 Bluemix:
    cf push  --no-start

    请记住选择一个不同的主机名,这样您最终的 URL 路由就不会与演示 URL 发生冲突。将制图应用程序推送到 Bluemix 时,您会看到一个类似下图的屏幕。

    ‘cf push’ 命令的输出的屏幕截图
    ‘cf push’ 命令的输出的屏幕截图
  7. 创建 MongoDB 服务的一个实例。在终端中,转到项目根目录,键入以下命令来使用一个惟一名称创建一个 MongoDB 服务实例:
    cf create-service mongodb 100 mongodb001
  8. 键入以下命令,将该 MongoDB 服务实例绑定到新应用程序,在我们的例子中为 trendsapp001
    cf bind-service trendsapp001 mongodb001

    您也可以登录到 Bluemix 管理控制台并在 APPS 菜单下找到制图应用程序,以这种方式创建一个 MongoDB 服务实例。

    Bluemix 仪表板 - 应用程序清单
  9. 选择您的应用程序,在结果页面上,使用 Add Service 选项将 MongoDB 服务添加到您的应用程序中。 Bluemix 仪表板的屏幕截图 - 添加 MongoDB 作为服务
    Bluemix 仪表板的屏幕截图 - 添加 MongoDB 作为服务

    您现在应在 Bluemix 管理仪表板上看到一个绑定到您应用程序的 MongoDB 服务实例。

    Bluemix 仪表板的屏幕截图 - 列出绑定的服务
    Bluemix 仪表板的屏幕截图 - 列出绑定的服务

    将 MongoDB 服务实例绑定到应用程序后,以下配置会添加到您的 VCAP_SERVICES 环境变量中:

    Bluemix 仪表板 - 环境变量
    Bluemix 仪表板 - 环境变量
  10. 运行以下命令来启动该应用程序。
    cf start trendsapp001
  11. 通过访问 trendsapp001.mybluemix.net/trends 来访问您的制图应用程序(将 trendsapp001 替换为您在 manifest.yml 文件中提供的惟一主机名)。另外,可以单击本文开头的 Run the app 按钮来尝试实时演示该应用程序。

    下面这个屏幕截图显示了应用程序中显示的美国的太阳能消耗情况图表。您可以单击屏幕右侧的菜单,打印该图表或以图像或 PDF 格式下载它。

    屏幕截图 - 能源消耗仪表板
    屏幕截图 - 能源消耗仪表板

结束语

本文演示了如何创建 Django 应用程序并将它部署在 Bluemix 平台上。我还介绍了使用 Bluemix MongoDB 服务作为数据缓存和将它与 Django 框架集成的详细信息。本文中提供的制图应用程序的源代码可以从其 JazzHub 存储库下载,您还可以下载正常运行它所需的所有配置文件。在构建这个制图应用程序后,您现在应能够将该过程应用到自己的项目中。您拥有无限的可能!


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Cloud computing
ArticleID=1000681
ArticleTitle=使用 Python、Django 和 MongoDB 在 Bluemix 上构建和部署一个基于 World Bank 数据的制图应用
publish-date=03172015