当前位置:   article > 正文

django创建应用程序_使用Django和jQuery创建电子表格应用程序

django jqgrid

django创建应用程序

本文介绍如何使用jQuery,jQuery插件和Django实现基于Web的简单电子表格。 这绝不是完整的尝试,也不是与Google Docs竞争的尝试,而只是证明了当今存在大量jQuery插件和工具的情况下创建“办公室”风格的Web应用程序是多么容易。 我在后端使用了SQLite / Python / Django堆栈,但是您可以轻松地移植到另一个框架,例如Ruby on Rails。

项目依赖

本文使用以下Python技术(请参阅参考资料中的链接):

  • Python 2.5以上
  • simplejson
  • Django 1.2.3

注意: Python 2.5不包含simplejson,但它包含在更高的Python版本中。

如果你不想去通过让所有的jQuery的依赖关系的麻烦,随时免费下载使用的连接器的完整演示相关主题 。 在前端,您需要以下技术:

  • jQuery 1.4.3
  • jQuery UI 1.8.5
  • SlickGrid
  • jQuery JSON

所有这些第三方库都可以为您处理大部分工作量,尤其是SlickGrid。 我之所以选择使用SlickGrid是因为它具有突出显示/选择单元格组的功能,以防我想提高单元格的数学运算和解析能力。 它还允许您在滚动时加载数据。 还可以使用其他几种出色的jQuery网格,包括Flexigrid,jQuery Grid,jqGridView和Ingrid。 此外,jQuery项目还宣布了官方jQuery Grid插件的计划。

试算表规格

每个电子表格包含一个工作簿,每个工作簿包含一个或多个数据表。 当输入的第一个字符是等号( = )时,工作表中的每个单元格都应执行算术运算。 否则,输入的文本应保持原样。 数据被加载到JSON对象中,异步发送到后端,然后保存到数据库。 电子表格将处理“打开”,“新建”和“保存”操作,并且工作簿的名称显示在顶部的可编辑文本框中。

单击“ 打开”将打开一个jQuery UI窗口,该窗口显示数据库中的现有工作簿。 选择工作簿后,使用异步JavaScript和XML(Ajax)检索存储的JSON数据并将其呈现到网格中。 保存以异步方式将JSON格式的网格数据发送到后端进行存储。 “新建”操作将删除所有引用并重新加载干净的工作簿。

最后,工作簿的工作表分为不同的jQuery UI选项卡。 与其他任何电子表格一样,这些选项卡显示在底部,并通过单击底部的按钮动态添加。

项目结构

您将所有CSS / JavaScript /图像放置在项目顶层的资源文件夹下。 Django应用程序将包含一个名为index.html的模板,该模板不过是一点点标记,因为您希望保持HTML语义和JavaScript代码非侵入性。 诸如网格之类的组件创建是动态完成的。 电子表格定义包含在一个名为sheetsheet.js的文件中。

创建Django后端

首先,通过发出以下命令来创建Django项目:

django-admin startproject spreadsheet

然后,通过调用以下命令,将Cd放入新创建的项目中以创建应用程序:

django-admin startapp spreadsheet_app

本文使用SQLite3来避免进行额外的数据库工作,但可以随意使用您喜欢的任何关系数据库系统(RDBS)。 修改settings.py文件以使用清单1中的代码。

清单1. Django settings.py文件
  1. import os
  2. APPLICATION_DIR = os.path.dirname( globals()[ '__file__' ] )
  3. DATABASES = {
  4. 'default': {
  5. 'ENGINE': 'django.db.backends.sqlite3',
  6. 'NAME': 'db',
  7. 'USER': '',
  8. 'PASSWORD': '',
  9. 'HOST': '',
  10. 'PORT': '',
  11. }
  12. }
  13. MEDIA_ROOT = os.path.join( APPLICATION_DIR, 'resources' )
  14. MEDIA_URL = 'http://localhost:8000/resources/'
  15. ROOT_URLCONF = 'spreadsheet.urls'
  16. TEMPLATE_DIRS = (
  17. os.path.join( APPLICATION_DIR, 'templates' ),
  18. )
  19. INSTALLED_APPS = (
  20. 'django.contrib.auth',
  21. 'django.contrib.contenttypes',
  22. 'django.contrib.sessions',
  23. 'django.contrib.sites',
  24. 'django.contrib.messages',
  25. 'spreadsheet_app',
  26. )

您无需在settings.py文件中修改任何其他变量。 现在,配置URL映射。 在这种情况下,仅需要两个映射:一个用于静态服务的文件,另一个指向索引。 清单2显示了代码。

清单2. urls.py文件
  1. from django.conf.urls.defaults import *
  2. from django.conf import settings
  3. import spreadsheet.spreadsheet_app.views as views
  4. urlpatterns = patterns('',
  5. ( r'^resources/(?P<path>.*)$',
  6. 'django.views.static.serve',
  7. { 'document_root': settings.MEDIA_ROOT } ),
  8. url( r'^spreadsheet_app/', views.index, name="index" ) ,
  9. )

在项目的顶层创建一个名为资源的目录,并在其子目录中创建名为css,js和images的子目录。 下载的依赖项(例如SlickGrid)以及应用程序的自定义JavaScript代码都存储在此处。 如果您感到懒惰,只需下载演示并复制资源目录即可。

接下来,创建您的域模型(请参见清单3)。 该模型将仅包含三个字段: workbook_namesheet_namedata 。 Django对象关系映射器(ORM)自动创建一个名为id的键字段。

清单3. models.py文件
  1. # file: spreadsheet_app/models.py
  2. from django.db import models
  3. class Workbooks(models.Model):
  4. workbook_name = models.CharField(max_length=30)
  5. sheet_name = models.CharField(max_length=30)
  6. data = models.TextField()

如您所知,您没有充分利用Django的全部功能。 您只希望它处理后端工作,而将繁重的工作留给jQuery前端。

最后,创建索引视图。 索引视图处理您对电子表格的创建/读取/更新操作。 在不涉及索引视图的所有细节的情况下,清单4展示了如何处理传入请求的基础。

清单4.视图
  1. # file:spreadsheet_app/views.py
  2. from django.template.context import RequestContext
  3. from spreadsheet.spreadsheet_app.models import Workbooks
  4. import simplejson as json
  5. from django.http import HttpResponse
  6. def index(request):
  7. app_action = request.POST.get('app_action')
  8. posted_data = request.POST.get('json_data')
  9. if posted_data is not None and app_action == 'save':
  10. ...
  11. elif app_action == 'get_sheets':
  12. ...
  13. elif app_action == 'list':
  14. ...

导入之后,您会看到索引视图接受一个请求对象,该对象包含从客户端发送的发布数据。 您将获得两个参数: app_actionposted_dataapp_action参数告诉您客户端请求的操作,例如创建新的工作簿。 posted_data参数是从客户端发送的一张工作表的JSON数据。 不同的动作由一个简单的if语句处理; 您可以保存工作表,获取工作簿的所有工作表,或获取数据库中工作簿的列表。

您稍后将返回索引视图以查看详细信息。 现在,在sheetsheets_app目录中添加一个名为模板的目录。 在模板子目录中,添加一个名为index.html的文件,这是项目中唯一的模板。 清单5显示了代码。

清单5.索引模板
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  2. "http://www.w3.org/TR/html4/strict.dtd">
  3. <html>
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"i>
  6. <title>Overly Simple Spreadsheet</title>
  7. <link rel="stylesheet" href="{{MEDIA_URL}}css/smoothness/jquery-ui-1.8.5.custom.css"
  8. type="text/css" media="screen" charset="utf-8" />
  9. <link rel="stylesheet" href="{{MEDIA_URL}}css/slick.grid.css" type="text/css"
  10. media="screen" charset="utf-8" />
  11. <link rel="stylesheet" href="{{MEDIA_URL}}css/examples.css" type="text/css"
  12. media="screen" charset="utf-8" />
  13. <link rel="stylesheet" href="{{MEDIA_URL}}css/spreadsheet.css" type="text/css"
  14. media="screen" charset="utf-8" />
  15. <script type="text/javascript" src="{{MEDIA_URL}}js/jquery-1.4.3.min.js"></script>
  16. <script type="text/javascript" src="{{MEDIA_URL}}js/jquery.json.js"></script>
  17. <script type="text/javascript" src="{{MEDIA_URL}}js/jquery-ui-1.8.5.custom.min.js">
  18. </script>
  19. <script type="text/javascript" src="{{MEDIA_URL}}js/jquery.event.drag-2.0.min.js">
  20. </script>
  21. <script type="text/javascript" src="{{MEDIA_URL}}js/ui/jquery.ui.tabs.js"></script>
  22. <script type="text/javascript" src="{{MEDIA_URL}}js/slick.editors.js"></script>
  23. <script type="text/javascript" src="{{MEDIA_URL}}js/slick.grid.js"></script>
  24. <script type="text/javascript" src="{{MEDIA_URL}}js/spreadsheet.js"></script>
  25. </headi>
  26. <body>
  27. </body>
  28. </html>

如您所见,HTML中没有控件逻辑或样式,只是标记。 事实上,身体中甚至没有任何元素。 所有这些都是由JavaScript代码即时生成的。 这个想法是通过方法调用来添加和删除元素。

电子表格.js的鸟瞰图

加载后,电子表格将呈现UI并加载单个选项卡。 清单6显示了render_ui的代码。

清单6.电子表格.js中的render_ui方法
  1. function render_ui(){
  2. insert_menu_markup();
  3. insert_grid_markup();
  4. make_grid_component();
  5. add_newtab_button();
  6. insert_open_dialog_markup();
  7. make_open_dialog();
  8. }

让我们以insert_menu_markup开头, insert_menu_markup每种方法的操作方式。 此方法仅添加了顶部菜单HTML代码,如清单7所示。该菜单由三个按钮(新建,打开和保存)以及用于显示和输入工作簿名称的文本字段组成。 您使用jQuery prepend来确保添加标记时,它将作为正文中的第一个元素插入。

清单7.生成菜单标记的方法
  1. // OK, it's not really a menu...yet :-)
  2. function insert_menu_markup(){
  3. $("body").prepend(
  4. '<input type="text" id="workbook_name" name="workbook_name" value="">');
  5. $("body").prepend('<input id="save" type="button" value="save"/>');
  6. $("body").prepend('<input id="open" type="button" value="open"/>');
  7. $("body").prepend('<input id="new" type="button" value="new"/>');
  8. }

图1显示了非常简单的菜单,它实际上只是一些按钮和一个文本框。

图1.菜单
具有3个标签的电子表格:“新建”,“打开”和“保存”,以及invoices_2010的名称。

insert_grid_markup方法类似于insert_menu_markup ,但是这次您使用append方法。 jQuery UI需要<div>的列表来生成选项卡小部件:

  1. function insert_grid_markup(){
  2. var workbook_widget = '<div id="tabs" class="tabs-bottom"><ul><li></li></ul></div>';
  3. $('body').append(workbook_widget);
  4. }

现在,通过调用方法make_grid_component使选项卡make_grid_component 。 清单8显示了代码。

清单8.将表格div更改为选项卡
  1. function make_grid_component(){
  2. $("#tabs").tabs();
  3. $(".tabs-bottom .ui-tabs-nav, .tabs-bottom .ui-tabs_nav > *")
  4. .removeClass("ui-corner-all ui-corner-top")
  5. .addClass("ui-corner-bottom");
  6. }

您使用jQuery id选择器获取对选项卡<div>的引用,然后调用tabs()方法将<div>转换为选项卡小部件。 删除默认CSS类ui-corner-top ,然后添加ui-corner-bottom类,以便选项卡显示在底部,如图2所示。

图2.工作簿选项卡
显示三个标签,名称分别为Sheet 0,Sheet 1,Sheet 2。

该组件是所有数据网格的容器。 现在,在选项卡组件下添加一个按钮,该按钮将在每次单击时动态添加一个选项卡。 您可以使用add_newtab_button方法执行此add_newtab_button

  1. function add_newtab_button(){
  2. $('body').append('<input id="new_tab_button" type="button" value="+"/>');
  3. }

最后一个要创建的可视组件是Open窗口,您可以通过调用清单9中所示的方法insert_open_dialog_markup来创建该窗口。与其他insert标记方法一样,该窗口创建一个包含标记信息的字符串并将其附加到正文中。

清单9.生成对话框标记的方法
  1. function insert_open_dialog_markup(){
  2. var dlg = '<div id="dialog_form" title="Open">' +
  3. '<div id="dialog_form" title="Open">' +
  4. '<p>Select an archive.</p><form>'+
  5. '<select id="workbook_list" name="workbook_list">' +
  6. '</select></form></div>';
  7. $("body").append(dlg);
  8. }

现在,这个窗口的标记是存在的,你用增加它的功能make_open_dialog清单10的去年方法所示方法render_ui 。 通过调用.dialog()方法并向其传递参数autoOpen:false ,除非明确打开表单,否则该表单不会显示在网页上。 对话框窗体包含一个选择列表,其中包含加载时工作簿名称的列表。

清单10.使“打开”窗口起作用
  1. function make_open_dialog(){
  2. $('#dialog_form').dialog({
  3. autoOpen: false,
  4. modal: true,
  5. buttons: {
  6. "OK":function(){
  7. selected_wb = $('option:selected').attr('value');
  8. $(this).dialog('close');
  9. // remove grid, existing forms, and recreate
  10. $('body').html('');
  11. render_ui();
  12. // load grids and create forms with invisible inputs
  13. load_sheets(selected_wb);
  14. // place workbook name in text field
  15. $('#workbook_name').val(selected_wb);
  16. },
  17. "Cancel":function(){
  18. $(this).dialog('close');
  19. }
  20. }
  21. });
  22. }

您再次使用jQuery选择器来获取dialog_form的句柄并调用dialog()方法,该方法将html元素转换为jQuery窗口。 “打开”窗口是模式窗口,在页面加载时不会打开。 它还包含两个按钮-确定和取消。 后者只不过是关闭窗口而已。 OK函数在选择列表中找到所选项目并获取其值。 然后,它关闭窗口,删除主体中的所有子元素,重新渲染GUI组件,并加载工作表(或者,如果您更喜欢用术语SlickGrids )。 如前所述,由于标记的生成全部在方法中,因此添加和删除这些窗口小部件组件现在变得无关紧要。

呈现UI基础之后,您现在编写一种用于使用网格打开新选项卡的方法。 继续从上至下的方法,清单11显示了openTab方法,这是此应用程序中的关键功能。

注意:应用程序中的每个工作表都包含一个遵循简单约定的ID:tabs_,后跟工作表中的标签号。

清单11.向工作簿添加新标签的方法
  1. function openTab(sheet_id) {
  2. numberOfTabs = $("#tabs").tabs("length");
  3. tab_name = "tabs_" + numberOfTabs;
  4. $("#tabs").tabs("add","#" + tab_name,"Sheet " + numberOfTabs, numberOfTabs);
  5. $("#" + tab_name).css("display","block");
  6. $("#tabs").tabs("select",numberOfTabs);
  7. $('#'+tab_name ).css('height','80%');
  8. $('#'+tab_name ).css('width','95%');
  9. $('#'+tab_name ).css('float','left');
  10. add_grid(tab_name, numberOfTabs);
  11. // add form for saving this tabs data
  12. if(!sheet_id){
  13. $('body').append(
  14. '<form method="post" action="?" id="'+tab_name +'_form" name="'+tab_name+'_form">'+
  15. '<input type="hidden" id="data'+numberOfTabs+'" name="data'+numberOfTabs+'" value="">'+
  16. '<input type="hidden" id="sheet_id" name="sheet_id" value="">' +
  17. '</form>');
  18. } else {
  19. $('body').append(
  20. '<form method="post" action="?" id="'+tab_name +'_form" name="'+tab_name+'_form">' +
  21. '<input type="hidden" id="data'+numberOfTabs +'" name="data'+numberOfTabs+'" value="">'+
  22. '<input type="hidden" id="sheet_id" name="sheet_id" value="'+sheet_id+'">' +
  23. '</form>');
  24. }
  25. }

如果您感兴趣,一种编码标记字符串的好方法是使用某种JavaScript模板,而不是将字符串串联在一起。 唯一的工作表ID被保存到隐藏的input元素中。 您还添加了一个隐藏元素,用于保存JSON数据。 隐藏的输入遵循简单的命名约定-数据后跟制表符编号。 要注意的另一个重要点是,新添加的选项卡在添加实际的SlickGrid之前已对其CSS属性进行了修改。 如果不这样做,则网格将无法正确渲染。

openTab方法调用add_grid方法,该方法执行SlickGrid对象的实际实例化。 清单12显示了该应用程序的繁重工作。 创建两个JavaScript对象- workbookgrid_referencesWorkbook对象包含对当前workbook对象的引用,而grid_references包含对每个SlickGrid对象的引用。 add_grid方法接受两个参数:网格名称和网格编号。

在列定义中,您希望使用SlickGrid示例之一中提供的TextCellEditor作为默认值(从a到p)有16列。 在列定义之后,将参数定义提供给SlickGrid。 单元格是可编辑的,可调整大小的和可选的。 确认asyncEditorLoading选项设置为True很重要,这可以让您在网格上实现Ajax操作。

清单12.将SlickGrids添加到您的应用程序
  1. var workbook = {};
  2. var grid_references = {};
  3. function add_grid(grid_name, gridNumber){
  4. var grid;
  5. var current_cell = null;
  6. // column definitions
  7. var columns = [
  8. {id:"row", name:"#", field:"num", cssClass:"cell-selection", width:40,
  9. cannotTriggerInsert:true, resizable:false, unselectable:true },
  10. {id:"a", name:"a", field:"a", width:70, cssClass:"cell-title",
  11. editor:TextCellEditor},
  12. {id:"b", name:"b", field:"b", width:70, cssClass:"cell-title",
  13. editor:TextCellEditor},
  14. {id:"c", name:"c", field:"c", width:70, cssClass:"cell-title",
  15. editor:TextCellEditor},
  16. {id:"d", name:"d", field:"d", width:70, cssClass:"cell-title",
  17. editor:TextCellEditor},
  18. {id:"e", name:"e", field:"e", width:70, cssClass:"cell-title",
  19. editor:TextCellEditor},
  20. {id:"f", name:"f", field:"f", width:70, cssClass:"cell-title",
  21. editor:TextCellEditor},
  22. {id:"g", name:"g", field:"g", width:70, cssClass:"cell-title",
  23. editor:TextCellEditor},
  24. {id:"h", name:"h", field:"h", width:70, cssClass:"cell-title",
  25. editor:TextCellEditor},
  26. {id:"i", name:"i", field:"i", width:70, cssClass:"cell-title",
  27. editor:TextCellEditor},
  28. {id:"j", name:"j", field:"j", width:70, cssClass:"cell-title",
  29. editor:TextCellEditor},
  30. {id:"k", name:"k", field:"k", width:70, cssClass:"cell-title",
  31. editor:TextCellEditor},
  32. {id:"l", name:"l", field:"l", width:70, cssClass:"cell-title",
  33. editor:TextCellEditor},
  34. {id:"m", name:"m", field:"m", width:70, cssClass:"cell-title",
  35. editor:TextCellEditor},
  36. {id:"n", name:"n", field:"n", width:70, cssClass:"cell-title",
  37. editor:TextCellEditor},
  38. {id:"o", name:"o", field:"o", width:70, cssClass:"cell-title",
  39. editor:TextCellEditor},
  40. {id:"p", name:"p", field:"p", width:70, cssClass:"cell-title",
  41. editor:TextCellEditor},
  42. ];
  43. var options = {
  44. editable: true,
  45. autoEdit: true,
  46. enableAddRow: true,
  47. enableCellNavigation: true,
  48. enableCellRangeSelection : true,
  49. asyncEditorLoading: true,
  50. multiSelect: true,
  51. leaveSpaceForNewRows : true,
  52. rerenderOnResize : true
  53. };
  54. eval("var data" + gridNumber + " = [];");
  55. workbook["data" + gridNumber] = [];
  56. for( var i=0; i < 100 ; i++ ){
  57. var d = (workbook["data"+gridNumber][i] = {});
  58. d["num"] = i;
  59. d["value"] = "";
  60. }
  61. grid = new Slick.Grid($("#"+grid_name),workbook["data"+gridNumber], columns, options);
  62. ...

您使用eval语句以某种“变态”的方式动态创建变量名。 然后使用空字符串数据加载data变量,并创建一个SlickGrid实例。

现在,向事件添加网格attach ,如清单13所示。当onCurrentCellChanged事件发生时,它将获取网格数据并更新单元格内容。 在单元格编辑完成之前,将调用onBeforeCellEditorDestroy事件。 触发后,您将像以前一样获取单元格数据,但是这次,您将确定第一个字符是否为等号。 如果是这样,请使用JavaScript eval方法评估输入的表达式。

警告:请勿在生产环境中使用此代码。 它将使您的系统容易受到各种讨厌的注入攻击。 始终清理数据。

最后,保存对网格的引用以用于其他方法。

清单13.将事件处理添加到网格
  1. // file: resources/js/spreadsheet.js continued
  2. // Events
  3. grid.onCurrentCellChanged = function(){
  4. d = grid.getData();
  5. row = grid.getCurrentCell().row;
  6. cell = grid.getCurrentCell().cell;
  7. this_cell_data = d[row][grid.getColumns()[cell].field];
  8. };
  9. grid.onBeforeCellEditorDestroy = function(){
  10. d = grid.getData();
  11. row = grid.getCurrentCell().row;
  12. cell = grid.getCurrentCell().cell;
  13. this_cell_data = d[row][grid.getColumns()[cell].field];
  14. if(this_cell_data && this_cell_data[0] === "="){
  15. // evaluate JavaScript expression, don't use
  16. // in production!!!!
  17. eval("var result = " + this_cell_data.substring(1));
  18. d[row][grid.getColumns()[cell].field] = result;
  19. }
  20. };
  21. grid_references[grid_name] = grid;
  22. };

回到规范,您的电子表格必须创建一个新工作簿以及保存并打开现有工作簿。 让我们实现新的工作簿功能,这是三个任务中最简单的一个。 在这里,您所需要做的就是销毁UI和所有引用,然后重新绘制,如清单14所示。

清单14.创建一个新的工作簿
  1. $('#new').live('click', function(){
  2. // delete any existing references
  3. workbook = {};
  4. grid_references = {};
  5. // remove grid, existing forms, and recreate
  6. $('body').html('');
  7. // recreate
  8. render_ui();
  9. openTab();
  10. });

“保存”功能稍微复杂一些。 您使用jQuery选择器获取具有以data开头的name属性的每个元素,然后使用each方法遍历结果集。 要注意的最关键的事情是,使用jquery.json插件将网格数据编码为JSON格式,以便“通过网络”发送。 您可以使用$.post方法异步发送数据。 传递到索引视图的参数是要执行的操作(在本例中,如清单15所示,保存),唯一的工作表ID,工作簿名称以及JSON格式的网格数据。

清单15.保存网格数据
  1. $('#save').live('click',function(){
  2. // Do a foreach on all the grids. The ^= operator gets all
  3. // the inputs with a name attribute that begins with data
  4. $("[name^='data']").each(function(index, value){
  5. var data_index = "data"+index;
  6. var sheet_id = $('#tabs_'+index+'_form').find('#sheet_id').val();
  7. if(sheet_id !== ''){
  8. sheet_id = eval(sheet_id);
  9. }
  10. // convenience variable for readability
  11. var data2post = $.JSON.encode(workbook[data_index]);
  12. $("#"+data_index).val(data2post);
  13. $.post( '{% url index %}', {'app_action':'save', 'sheet_id': sheet_id,
  14. 'workbook_name':$('#workbook_name').val(),
  15. 'sheet':data_index, 'json_data':data2post});
  16. });
  17. });

回想一下,打开需要使用load_sheets方法。 现在添加该方法(请参见清单16)。 此方法必须调用后端,以将传递给该工作簿的工作表的所有工作表请求给工作表。 然后将数据加载到相应的SlickGrid对象中。 请注意,在将数据插入对象之前,必须使用decode方法对JSON数据进行反序列化。 然后渲染网格。

清单16.将数据加载到网格中
  1. function load_sheets(workbook_name){
  2. $('#workbook_list').load('{% url index %}',
  3. {'app_action':'get_sheets','workbook_name':workbook_name},
  4. function(sheets, resp, t){
  5. sheets = $.JSON.decode(sheets);
  6. workbook = {}; // reset
  7. grid_references = {};
  8. $.each(sheets, function(index, value){
  9. // add to workbook object
  10. var sheet_id = value["sheet_id"];
  11. openTab(sheet_id);
  12. // By calling eval, we translate value from
  13. // a string to a JavaScript object
  14. workbook[index] = eval(value["data"]);
  15. // insert data into hidden
  16. $("#data"+index).attr('value', workbook[index]);
  17. grid_references["tabs_"+index].setData(workbook[index]);
  18. grid_references["tabs_"+index].render();
  19. });
  20. });
  21. }

最后但并非最不重要的一点是,您实现了open函数。 再次,进行异步调用,这次发送list操作,然后再次反序列化以JSON发送的数据。 然后,使用数据库中所有工作簿的名称更新select列表。 然后打开对话框。 清单17显示了代码。

清单17.打开一个现有的工作簿
  1. $('#open').live('click',function(){
  2. // load is used for doing asynchronous loading of data
  3. $('#workbook_list').load('{% url index %}', {'app_action':'list'},
  4. function(workbooks,success){
  5. workbooks = $.JSON.decode(workbooks);
  6. $.each(workbooks, function(index, value){
  7. $('#workbook_list').append(
  8. '<option value="'+ value +'">'+value +'*lt;/option>');
  9. });
  10. });
  11. $('#dialog_form').dialog('open');
  12. });

重新查看索引视图

现在,您已经对客户端发布进行了编码,您可以完成索引视图。 清单18显示了完整的索引视图,除了导入。

要(反)序列化JSON代码,请使用simplejson模块,然后命令转储对其进行序列化以及反向加载。 对于“保存”操作,如果为单个工作表指定了ID,则会更新工作表。 否则,将创建一个新工作表。

相反,“获取工作表”操作将创建一个JSON对象,其中包含特定工作簿的所有工作表。 它使用filter()命令检索工作簿的所有工作表( QuerySet对象)。 这等效于select * from spreadsheet_app_workbooks workbook_name = wb_name" select * from spreadsheet_app_workbooks ,其中workbook_name = wb_name" 。检索到集合后,您可以将它们再次转换为JSON格式,然后将其发送回客户端。

List还使用Django ORM,但这一次使用values()方法。 在这里,您告诉Django,“获取workbook_name列”。 通过在QuerySet对象上调用distinct方法,您明确表示您不需要任何重复项。 您再次使用列表推导根据结果创建列表。 对于get_sheetslist ,您必须为jQuery返回HttpResponse对象,以处理您的Ajax响应。

清单18.视图完成
  1. def index(request):
  2. template = 'index.html'
  3. app_action = request.POST.get('app_action')
  4. posted_data = request.POST.get('json_data')
  5. if posted_data is not None and app_action == 'save':
  6. this_sheet = request.POST.get("sheet")
  7. this_workbook = request.POST.get("workbook_name")
  8. sheet_id = request.POST.get("sheet_id")
  9. posted_data = json.dumps(posted_data)
  10. if(sheet_id):
  11. wb = Workbooks(id=sheet_id, workbook_name=this_workbook,
  12. sheet_name=this_sheet, data=posted_data)
  13. else:
  14. wb = Workbooks(workbook_name=this_workbook,
  15. sheet_name=this_sheet, data=posted_data)
  16. wb.save()
  17. elif app_action == 'get_sheets':
  18. wb_name = request.POST.get('workbook_name')
  19. sheets = Workbooks.objects.filter(workbook_name=wb_name)
  20. # use list comprehension to create python list which is like a JSON object
  21. sheets = [{ "sheet_id":i.id, "workbook_name": i.workbook_name.encode("utf-8"),
  22. "sheet_name": i.sheet_name.encode("utf-8"),
  23. "data": json.loads(i.data.encode("utf-8"))} for i in sheets ]
  24. # dumps -> serialize to JSON
  25. sheets = json.dumps(sheets)
  26. return HttpResponse( sheets, mimetype='application/javascript' )
  27. elif app_action == 'list':
  28. workbooks = Workbooks.objects.values('workbook_name').distinct()
  29. # use list comprehension to make a list of just the work books names
  30. workbooks = [ i['workbook_name'] for i in workbooks ]
  31. # encode into json format before sending to page
  32. workbooks = json.dumps(workbooks)
  33. # We need to return an HttpResponse object in order to complete
  34. # the ajax call
  35. return HttpResponse( workbooks, mimetype='application/javascript' )
  36. return render_to_response(template, {},
  37. context_instance = RequestContext( request ))

完成网格

现在,您已经定义了所有JavaScript方法,可以使用两个方法调用来生成应用程序,如清单19所示。

清单19.加载页面时执行的代码
  1. $(document).ready(function(){
  2. render_ui();
  3. openTab();
  4. });

页面加载完成后,将呈现UI,并将新的选项卡插入工作簿。

现在,您可以在命令行中运行python manage syncdb来创建数据库,以查看其电子表格应用程序的全部(缺少)功能。 完成后,执行命令python manage.py runserver并导航到http://localhost:8000/spreadsheet_app 。 您应该看到最终版本,如图3所示。

图3.完整的电子表格应用程序
包含7列14行的电子表格,并填写了客户信息。

您可以在这个项目中添加很多东西,但是我不得不施加一些自我约束。 例如,您可以包括:

  • 情节
  • 一个安全,功能更强大的解析器,用于输入到每个单元格中的公式
  • 导出为其他格式,例如Microsoft®Office Excel
  • 使用其他jQuery插件的真实菜单

结论

尽管此Web应用程序尚未投入生产,但它演示了如何结合多种技术。 使用不引人注目JavaScript,语义HTML,JSON对象以异步方式从服务器来回传递数据,并且-尤其值得注意的是-当有许多可用的jQuery插件时,不浪费时间,这使您的工作变得更加轻松。


翻译自: https://www.ibm.com/developerworks/web/library/wa-django/index.html

django创建应用程序

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号