пятница, 12 февраля 2010 г.

Симпатичная форма обратной связи средствами Flex и Django

Доброго времени суток!



При написании данной статьи ставилась цель описать законченный пример использования двух фреймворков Flex и Django, а так же показать процесс разработки с их помощью небольшого приложения от начала и до конца.

notepad     post



Задача


Реализовать форму обратной связи для отсылки пользовательских сообщений администратору сайта.

Пояснение


Связка Flex и Django может показаться нерациональной для решения данной задачи, ведь с ней вполне можно справится с помощью HTML и одного скрипта на PHP. Так и есть. :) На этой небольшой задаче я постараюсь рассмотреть минимум необходимый для работы с этими замечательными фреймворками в связке.

От автора


Статья будет интересна тем, кто еще только присматривается к Flex и Django, но не пробовал их в деле. К статье прилагаются полные исходные коды сервера и клиента. Их можно скачать отсюда SendFormFlexDjango.zip. В силу специфики задачи серверная часть примера получилась очень маленькой, так что большая часть статьи описывает создание Flex клиента.

Сразу отмечу, что я не спец по Flex и Django и, к сожалению, не могу сказать, что имею серьезный опыт в web-разработке. :) Дружу с Python уже более двух лет, хотя до недавнего времени не применял для web. Год назад я столкнулся с Flex и немного работал с ним. А несколько недель назад я начал разработку небольшого проекта, для реализации клиентской части которого решил использовать Flex/ActionScript 3.0, а для сервера Django/Python. После небольшого перерыва и без груза чужой кодовой базы, можно сказать начал знакомство с Flex заново, с более свежими ощущениями. :) С Django я ранее знаком не был, и в процессе изучения был приятно удивлен удобством этого фреймворка. На мой взгляд сочетание Flex и Django позволяет довольно быстро получить практический результат.

Из вещей которые мне больше всего понравились во Flex: декларативное описание интерфейса и Data binding. Эти особенности позволяют писать гибкий код и компактный. Что понравилось в Django так это обилие возможностей "из коробки" и прекрасная документация.


О себе немного рассказал. Технологии похвалил. Пора к делу!


Что потребуется для работы?


Для разработки клиента можно взять Trial-версию Adobe Flex Builder 3.

Однако, данной статье я буду использовать бесплатные инструменты FlashDevelop + Flex SDK.


Adobe Flex 3.5 SDK

Нужен для компиляции клиента.

Страница загрузки.


FlashDevelop

Бесплатная среда разработки. На данный момент лучшая бесплатная IDE для ActionScript и Flex. В сравнении с Flex Builder 3 очень аскетичная. К сожалению, хоть она и open source, но написана под .Net, и поддерживается только под Windows. Под Mono не проверял.

http://www.flashdevelop.org


Inkscape

Этот графический векторный редактор потребуется для редактирования и экспорта макета формы из формата svg. Макет в svg находится в архиве с исходниками для статьи. http://www.inkscape.org/


Aptana Studio или Eclipse совместно с дополнением Pydev.

http://www.aptana.org/

http://pydev.org/nightly


Python 2.6

Замечательный язык программирования. ;)

http://www.python.org/


Django 1.1.1

http://www.djangoproject.com/

Django-1.1.1.tar.gz


Для отладки может понадобиться Debug версия Flash Player. Различные версии Flash Player можно скачать здесь

Я скачал Standalone версию плеера, просто закинул его в Program Files и сопоставил для открытия swf файлов.

Огорчает лишь, что по умолчанию Flash Develop не содержит встроенного отладчика и умеет отображать только вывод функции trace().

Отладочного вывода через trace() должно хватать для большинства задач.


Для вывода сложных объектов можно использовать функцию mx.utils.ObjectUtil.toString(obj).

Если же не доступна отладочная версия плеера (нельзя просмотреть вывод функции trace() ), то можно воспользоваться стандартной функцией показа сообщений mx.controls.Alert.show(msg).

Пишем клиентскую часть


Подготовка


Для разработки клиентской части нам потребуется FlashDevelop, Inkscape и Flex SDK.

Распакуем Flex SDK куда-нибудь и настроим в FlashDevelop путь к нему:

Tools->Programm Settings->AS3Context->Flex SDK Location


Шаг 1


Создадим в FlashDevelop проект Flex 3 Project с именем feedback_client (Project->New Project).



post



Новый проект содержит файл Main.mxml, откроем его и вставим следующий код:


  1. <?xml version="1.0" encoding="utf-8"?>

  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300">

  3.   <mx:VBox x="0" y="0" width="100%" height="100%" horizontalAlign="center">

  4.     <mx:HBox width="100%">

  5.       <mx:Label text="Имя" width="15%"/>

  6.       <mx:TextInput id="nameTxt" width="100%" maxChars="40" />

  7.     </mx:HBox>

  8.     <mx:HBox width="100%">

  9.       <mx:Label text="e-mail" width="15%"/>

  10.       <mx:TextInput id="emailTxt" width="100%" maxChars="40"/>

  11.     </mx:HBox>

  12.     <mx:TextArea id="msgTxt" width="100%" height="100%" maxChars="5000" />

  13.     <mx:Button id="sendBtn" label="Отправить" />

  14.   </mx:VBox>  

  15. </mx:Application>


* This source code was highlighted with Source Code Highlighter.

Описание приложения на Flex начинается с узла mx:Application.

В свойствах этого узла описываются габаритные размеры итоговой флэшl2;и и фоновый цвет. Application в программе на Flex может быть только один. Экземпляр текущего приложения всегда можно узнать из свойства mx.core.Application.application. Все остальные элементы управления добавляются как дочерние элементы Application.



В данном примере я использовал контейнеры VBox и HBox для автоматического выравнивания элементов интерфейса. Существует множество способов задавать размеры и положение объекта: x, y, left, right, top, bottom, width, height, horizontalCenter, verticalCenter. Что особенно удобно, так это возможность использования процентов для задания некоторых величин.



Для компиляции и запуска проекта нажмем F5 или кнопку на панели инструментов:



post



Если все в порядке, запустится Flash Player или браузер с нашим приложением:



post



Для простоты я не стал в примере использовать стандартные компоненты для создания форм и механизм валидации. Flex предоставляет довольно обширный набор компонентов пользовательского интерфейса. Создать простую форму для отправки сообщения не составляет труда, но с оформлением по умолчанию она смотрится слегка уныло.


Шаг 2


Попробуем исправить ситуацию, для этого добавим в наше приложение графику.

В качестве примера к статье прилагается, созданный в Inkscape, svg-файл с макетом формы отправки в виде блокнота.



Создадим в директории проекта feedback_client каталог assets в который будем помещать всю графику.

Подготовим графику для встраивания в приложение, экспортировав svg элементы макта в файлы png.

Откроем файл "notepad_src.svg" и экспортируем в png слой "Блокнот".

Для этого откроем окно со списком слоев Shift+Ctrl+L (Слой->Слои), снимем замок со слоя "Блокнот", а на остальные наоборот навесим. Выберем все Ctrl+A (Правка->Выделить все). Shift+Ctrl+E (Файл->экспортировать в растр). Нажать кнопку "Выделение" и поставить галочку экспортировать только выделение, чтобы фон не попал в растр. Выбираем где сохранить файл и жмем экспорт.



post



Аналогичным образом экспортируется еще три изображения разных состояний кнопки отправки.


Шаг 3


Изменим структур Main.mxml и опишем графику в css файле.



Чтобы не загромождать Main.mxml вынесем форму для ввода данных в отдельный компонент, в файл FormCanvas.mxml и создадим еще один компонент для отображения сообщений, StatusCanvas.mxml.



Cкажу пару слов о создании своих компонент.



Новые компоненты создавать в Flex проще простого. Однажды описав их в отдельном mxml файле их легко потом использовать где угодно как в других mxml так из ActionScript. Для получения нового компонента создается mxml файл и в качестве корневого узла указывается компонент от которого требуется наследоваться.

В нашем случае это будет mx:Canvas:


  1. <?xml version="1.0" encoding="utf-8"?>

  2. <!--src/NewComponent.mxml -->

  3. <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" >

  4.   <mx:Label id="mylabel" text="label"/>

  5. </mx:Canvas>


* This source code was highlighted with Source Code Highlighter.

Внутри этого узла можно размещать любые теги с описанием элементов управления. При компиляции mxml файла создается новый ActionScript класс с именем таким же как имя файла. Для элементов с указанным свойством id, автоматически создаются публичные свойства для доступа к ним из кода ActinScript и биндинга.

Пример использования:


  1. var nc:NewComponent = new NewComponent();

  2. this.addChild(nc); // добавление nc на отображаемый компонент

  3. /* отображение nc */

  4. Alert.show(nc.mylabel.text); //допустимо но объект nc уже должен быть отображен на экране


* This source code was highlighted with Source Code Highlighter.

Если nc еще не отображен в приложении, то его дочерние элементы еще не созданы и поле mylabel будет содержать null.

Переменные будут гарантированно доступны только после события creationComplete. (Хорошее описание этого процесса flex-component-lifecycle-overview)

Если требуется передать объекту параметры сразу при создании, следует описать внутри него свои свойства или поля посредством тега mx:Script (см. StatusCanvasScript.as и StatusCanvas.mxml ), они будут инициироваться в конструкторе. Можно проводить их обработку в обработчике события creationComplete, либо, пометив как [Bindable], биндить(BindingUtils.bindProperty()) непосредственно на элементы управления. Для простоты встраивания графики подключим ее через css. Создадим директорию styles и в ней файл main.css. Опишем css классы с картинкой нашего блокнота и скины для кнопки, используя ключевое слово Embed для встраивания графики в результирующий swf файл приложения:


  1. .notepadBg{

  2.   backgroundImage: Embed("../assets/notepad.png");

  3.   verticalScrollPolicy: off;

  4.   horizontalScrollPolicy: off;

  5. }

  6.  

  7. .sendButton

  8. {

  9.   upSkin: Embed("../assets/send_btn_active.png");

  10.   overSkin: Embed("../assets/send_btn_over.png");

  11.   downSkin: Embed("../assets/send_btn_down.png");  

  12.   disabledSkin:Embed("../assets/send_btn_active.png");

  13. }


* This source code was highlighted with Source Code Highlighter.

Теперь мы можем подключить наш css в любом mxml файле:
<mx:Style source="../styles/main.css"/>

И применять описанные в css классы к компонентам указывая имя класса в свойстве styleName:
<mx:Canvas styleName="notepadBg" width="400" height="500"/>

<mx:Button id="sendBtn" styleName="sendButton" />


Опишем классы для полей ввода: .textInput и .textArea.

Чтобы все выглядело натурально нужно сделать поля ввода прозрачными и убрать рамку фокуса:


  1. .textInput

  2. {  

  3.   backgroundAlpha: 0.0;

  4.   borderStyle: none;

  5.   focusAlpha: 0;

  6.   fontFamily: "Arial";

  7.   fontSize: 16;  

  8. }


* This source code was highlighted with Source Code Highlighter.

Для textArea вдобавок увеличим расстояния между строк:


  1. .textArea

  2. {

  3.   /*...*/

  4.   leading:8.6;

  5. }


* This source code was highlighted with Source Code Highlighter.

На время отладки, выставим значения backgroundAlpha и backgroundColor для удобства подгонки положения элементов:


  1. .textArea

  2. {

  3.   /*...*/

  4.   backgroundAlpha: 0.8;

  5.   backgroundColor: #ff0000;

  6.   /*...*/

  7. }

  8.  


* This source code was highlighted with Source Code Highlighter.

Подгоняем положение элементов экспериментируя со значениями координат и размерами элементов в FormCanvas.mxml.



После подгонки параметров получиться вот так:



post<


Шаг 4


Выставляем backgroundAlpha равное 0 и убираем backgroundColor из стилей .textInput и .textArea.

В итоге у нас получится вполне симпатичный и интерактивный результат:



post     post



После проделанных изменений наш проект будет выглядеть так:


  1. <?xml version="1.0" encoding="utf-8"?>

  2. <!--src/FormCanvas.mxml -->

  3. <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="500" styleName="notepadBg" >

  4.   <mx:Style source="../styles/main.css"/>

  5.   <mx:VBox left="40" top="60" right="50" >

  6.     <mx:HBox width="100%">

  7.       <mx:Label text="Имя:" width="18%" styleName="label" />

  8.       <mx:TextInput id="nameTxt" width="72%" maxChars="40" styleName="textInput"/>

  9.     </mx:HBox>

  10.     <mx:HBox width="100%">

  11.       <mx:Label text="e-mail:" width="18%" styleName="label" />

  12.       <mx:TextInput id="emailTxt" width="72%" maxChars="40" styleName="textInput"/>

  13.     </mx:HBox>

  14.     <mx:TextArea id="msgTxt" width="100%" height="268" maxChars="5000" styleName="textArea" />

  15.     <mx:Canvas width="100%">

  16.       <mx:Button id="sendBtn" label="" horizontalCenter="0" styleName="sendButton" />

  17.     </mx:Canvas>    

  18.   </mx:VBox>

  19. </mx:Canvas>


* This source code was highlighted with Source Code Highlighter.



  1. <?xml version="1.0" encoding="utf-8"?>

  2. <!--src/Main.mxml -->

  3. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:ns1="*"

  4.   width="400" height="500"

  5.   paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0"

  6.   horizontalScrollPolicy="off" verticalScrollPolicy="off"  

  7.   >

  8.   <mx:Style source="../styles/main.css"/>

  9.   <mx:Canvas left="0" top="0" right="0" bottom="0" horizontalScrollPolicy="off" verticalScrollPolicy="off">

  10.     <ns1:FormCanvas id="formCanvas" x="0" y="0" visible="true" />

  11.     <ns1:StatusCanvas id="statusCanvas" x="0" y="0" visible="false" />  

  12.   </mx:Canvas>  

  13. </mx:Application>


* This source code was highlighted with Source Code Highlighter.



  1. <?xml version="1.0" encoding="utf-8"?>

  2. <!--src/StatusCanvas.mxml -->

  3. <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="500" styleName="notepadBg">

  4.   <mx:Style source="../styles/main.css"/>

  5.   <mx:Text verticalCenter="0" horizontalCenter="0" selectable="false" styleName="label"

  6.         htmlText="Сообщение" />

  7.   <mx:Text horizontalCenter="0" bottom="110" styleName="label" selectable="false"

  8.         htmlText="Кликните чтобы продолжить." />

  9. </mx:Canvas>


* This source code was highlighted with Source Code Highlighter.



  1. /* styles/main.css */

  2.  

  3. .notepadBg{

  4.   backgroundImage: Embed("../assets/notepad.png");

  5.   verticalScrollPolicy: off;

  6.   horizontalScrollPolicy: off;

  7. }

  8.  

  9. .sendButton

  10. {

  11.   upSkin: Embed("../assets/send_btn_active.png");

  12.   overSkin: Embed("../assets/send_btn_over.png");

  13.   downSkin: Embed("../assets/send_btn_down.png");  

  14.   disabledSkin:Embed("../assets/send_btn_active.png");

  15. }

  16.  

  17. .textInput

  18. {

  19.   /*backgroundAlpha: 0.8;

  20.   backgroundColor:#ff0000;/*/

  21.   backgroundAlpha: 0.0; /*прозрачный фон*/

  22.   borderStyle: none;

  23.   focusAlpha: 0; /*убираем рамку фокуса*/

  24.   fontFamily: "Arial";

  25.   fontSize: 16;  

  26. }

  27.  

  28. .textArea

  29. {

  30.   /*backgroundAlpha: 0.8;

  31.   backgroundColor:#ff0000;*/

  32.   backgroundAlpha: 0.0;/*прозрачный фон*/

  33.   borderStyle: none;

  34.   focusAlpha: 0; /*убираем рамку фокуса*/

  35.   fontFamily: "Arial";

  36.   fontSize: 16;

  37.   leading:8.6; /*увеличиваем междустрочный интервал*/

  38. }

  39.  

  40. .label

  41. {

  42.   fontFamily: "Arial";

  43.   fontSize: 16;

  44.   fontWeight :bold;

  45.   textAlign: center;

  46. }

  47.  

  48. .labelGreen

  49. {

  50.   fontFamily: "Arial";

  51.   fontSize: 22;

  52.   fontWeight :bold;

  53.   textAlign: center;

  54.   color:#00ff00;

  55. }

  56.  

  57. .labelRed

  58. {

  59.   fontFamily: "Arial";

  60.   fontSize:22;

  61.   fontWeight :bold;

  62.   textAlign: center;

  63.   color:#ff0000;

  64. }


* This source code was highlighted with Source Code Highlighter.


Шаг 5


Интерфейс готов. Осталось написать логику обработки; и отправки данных. Для этого создадим два файла MainScript.as и StatusCanvasScript.as в которых будем писать ActionScript код для нашего приложения. Подключим их к mxml файлам добавив тег mx:Script

для Main.mxml:
<mx:Script source="MainScript.as"/>  

и для StatusCanvas.mxml:
<mx:Script source="StatusCanvasScript.as"/>  

После проделанных изменений FlashDevelop будет отображать наши as файлы как вложенные узлы родительских mxml в дереве проекта.



post



Заполним as файлы кодом:


  1. /* MainScript.as */

  2. import flash.events.MouseEvent;

  3. import mx.rpc.AsyncToken;

  4. import mx.rpc.events.FaultEvent;

  5. import mx.rpc.events.ResultEvent;

  6. import mx.rpc.http.mxml.HTTPService;

  7. import mx.controls.Alert;

  8.  

  9. private static const SERVER_URL:String = "http://127.0.0.1:8081/send";

  10. private var service: HTTPService = null;

  11.  

  12. private function complete():void

  13. {

  14.   service = new HTTPService();

  15.   service.url = SERVER_URL;

  16.   service.method = "POST";      

  17.   service.resultFormat = "text";

  18.     

  19.   formCanvas.sendBtn.addEventListener(MouseEvent.CLICK, sendBtnClick, false, 0, true );

  20.   statusCanvas.addEventListener(MouseEvent.CLICK, statusCanvasClick, false, 0, true );

  21. }

  22.  

  23. private function showStatus(status:int, msg:String = null):void {

  24.   statusCanvas.status = status;

  25.   if (msg) statusCanvas.msgHtml = msg;

  26.   statusCanvas.visible = true;

  27. }

  28.  

  29. private function sendBtnClick(event:MouseEvent):void

  30. {

  31.   if ((formCanvas.nameTxt.text == "") ||

  32.     (formCanvas.emailTxt.text == "")||

  33.     (formCanvas.msgTxt.text == ""))

  34.   {  

  35.     showStatus(StatusCanvas.EMPTY_FORM);    

  36.     return;

  37.   }

  38.   

  39.   formCanvas.enabled = false;    

  40.   sendForm();

  41. }

  42.  

  43. private function sendForm():void {

  44.   var params:Object = { name:formCanvas.nameTxt.text,

  45.               email:formCanvas.emailTxt.text,

  46.               msg:formCanvas.msgTxt.text};

  47.   

  48.   var token:AsyncToken = service.send(params);      

  49.   var responder:mx.rpc.Responder = new mx.rpc.Responder(onResult, onFault);

  50.   token.addResponder(responder);

  51. }

  52.  

  53.  

  54. private function statusCanvasClick(event:MouseEvent):void {

  55.   formCanvas.visible = true;

  56.   statusCanvas.visible = false;

  57. }

  58.  

  59. private function clearForm():void {

  60.   formCanvas.nameTxt.text = "";

  61.   formCanvas.emailTxt.text = "";

  62.   formCanvas.msgTxt.text = "";

  63. }

  64.  

  65. protected function onResult(event:ResultEvent):void

  66. {

  67.   formCanvas.enabled = true;    

  68.   

  69.   var xml:XML = new XML(event.result);

  70.   var code:int = int(xml.code);

  71.   switch(code) {

  72.     case 0:

  73.       showStatus(StatusCanvas.OK);

  74.       clearForm();

  75.       break;

  76.     case 1:

  77.       showStatus(StatusCanvas.MSG, xml.msg);

  78.       break;

  79.     default:

  80.       showStatus(StatusCanvas.ERROR);

  81.   }  

  82. }

  83.  

  84. protected function onFault(event:FaultEvent):void

  85. {  

  86.   formCanvas.enabled = true;

  87.   if (event.statusCode == 0)

  88.     showStatus(StatusCanvas.CONNECTION_ERROR);

  89.   else showStatus(StatusCanvas.ERROR);  

  90. }


* This source code was highlighted with Source Code Highlighter.



  1. /* StatusCanvasScript.as */

  2.  

  3. import mx.binding.utils.BindingUtils;

  4.  

  5. public static const OK:int = 0;

  6. public static const ERROR:int = 1;

  7. public static const CONNECTION_ERROR:int = 2;

  8. public static const MSG:int = 3;

  9. public static const EMPTY_FORM:int = 4;

  10.  

  11. private var _status:int = MSG;

  12.  

  13. [Bindable]

  14. public var msgHtml:String = "";

  15. [Bindable]

  16. public var msgStyleName:String = "labelGreen";

  17.  

  18. private function complete():void

  19. {

  20.   BindingUtils.bindProperty(msgTxt,'htmlText', this, 'msgHtml');

  21.   BindingUtils.bindProperty(msgTxt,'styleName', this, 'msgStyleName');

  22. }

  23.  

  24. public function set status(status:int):void{

  25.   _status = status;

  26.   

  27.   switch(status) {

  28.     case OK:

  29.       msgStyleName = "labelGreen";

  30.       msgHtml = "Сообщение успешно<br>отправленно";

  31.       break;

  32.     case ERROR:

  33.       msgStyleName = "labelRed";

  34.       msgHtml = "Ошибка!<br>Попробуйте позднее.";

  35.       break;

  36.     case CONNECTION_ERROR:

  37.       msgStyleName = "labelRed";

  38.       msgHtml = "Сервер<br>недоступен."

  39.       break;

  40.     case EMPTY_FORM:

  41.       msgStyleName = "labelRed";

  42.       msgHtml = "Заполните<br>все поля."

  43.       break;

  44.     default:

  45.       msgHtml = "";

  46.       msgStyleName = "label";

  47.       break;

  48.   }

  49. }

  50.  

  51. public function get status():int{

  52.   return _status;

  53. }


* This source code was highlighted with Source Code Highlighter.

Теперь нужно обязательно указать обработчики события creationComplete="complete()" у корневых элементов в Main.mxml и StatusCanvas.mxml и наше клиентское приложение готово.



Приведу модификации в упрощенном виде:


  1. <mx:Application сreationComplete="complete()" >

  2.   <!-- содержимое -->  

  3.   <mx:Script source="MainScript.as"/>  

  4. </mx:Application>





  1. <mx:Canvas creationComplete="complete()" >

  2.   <!-- содержимое -->

  3.   <mx:Script source="StatusCanvasScript.as"/> 

  4. </mx:Canvas>



Теперь при нажатии на кнопку Отправить мы можем насладится одним из двух сообщений.



post     post

Как видно из кода, приложение посредством обьекта класса HTTPService делает POST запрос на url http://127.0.0.1:8081/send передавая данные сообщения в переменных name, email и msg. Дело за малым написать обработчик этого запроса.



На этом с клиентом закончим, пора браться за сервер.

Пишем серверную часть


Подготовка


Установим Python, Django и Aptana Studio. Для установки Django нужно распаковать Django-1.1.1.tar.gz и выполнить:


python setup.py install.


Желательно так же добавить c:\Python26\Scripts\ в системную переменную PATH, чтобы было удобно использовать django-admin.py, который расположен по этому пути.

После этой манипуляции потребуется перезагрузка.

Создаем проект сервера


Откроем Aptana Studio и создадим новый проект для Python с именем feedback_server (File->New->Project->Pydev->Pydev Project)

Галочку с "Create default 'src'..." можно снять.



post



Запустим cmd.exe и перейдем в директорию проекта feedback_server. Создадим проект Django:


django-admin.py startproject server


Перейдем в созданную директорию server и создадим Django приложение feedbacks для обработки отправки сообщения:


manage.py startapp feedbacks


Обновим дерево проектов в Aptana (F5) и перейдем к свойствам проекта feedback_server(Alt+Enter). Установите кодировку проекта в utf-8 (Resources->Text file encoding) В разделе "Pydev - PYTHONPATH" нужно добавить созданную django-admin.py директорию Django проекта "feedback_server/server" (Add source folder)



post



В разделе "Run/Debug Settings" создаем новую конфигурацию запуска (New->Python Run).

В редакторе конфигурации запуска на вкладке Main:


  • Project: feedback_server

  • Main Module: ${workspace_loc:feedback_server/server/manage.py}


На вкладке Arguments:

  • Program arguments: runserver 8081 --noreload

  • Working directory->Other: ${workspace_loc:feedback_server/server}


post



post



При использовании sqlite в качестве СУБД, без указания "Working directory" в настройках запуска, файл базы будет искаться текущем в каталоге Aptana. А так как его там нет, будет создаваться пустой файл, что приведет к ошибке при первом же запросе к таблицам.

Настройка проекта Django


Файл settings.py


В начало файла вставим код (спасибо автору топика):


  1. import os

  2. def rel(*x):

  3.     return os.path.join(os.path.abspath(os.path.dirname(__file__)), *x)


* This source code was highlighted with Source Code Highlighter.



  1. #Настроим в качестве СУБД sqlite

  2. DATABASE_ENGINE = 'sqlite3'

  3. DATABASE_NAME = 'db.sqlite'

  4. DATABASE_USER = ''

  5. DATABASE_PASSWORD = ''

  6. DATABASE_HOST = '' 

  7. DATABASE_PORT = ''


* This source code was highlighted with Source Code Highlighter.

Для чистоты эксперимента отключим в проекте все лишнее, так как задача стоит довольно простая. :)

В списке MIDDLEWARE_CLASSES и INSTALLED_APPS закомментируем все элементы.

Добавим наше приложение "feedbacks" в INSTALLED_APPS
INSTALLED_APPS =(

    'server.feedbacks',

)

В список TEMPLATE_DIRS добавим строчку :
TEMPLATE_DIRS = (    

    rel('templates'),

)

Шаблоны xml-ответов


В директории проекта создадим соответствующую директорию "templates"'. С двумя файлами feedback_result.xml:


  1. <!-- feedback_result.xml -->

  2. <r>

  3. <code>{{code}}</code>

  4. <msg>{{msg}}</msg>

  5. </r>


и feedbacks.xml:


  1. <!-- feedbacks.xml -->

  2. <r>

  3. <feedbacks>

  4. {% for row in feedbacks %}

  5. <f>

  6.   <name>{{row.name}}</name>

  7.   <email>{{row.email}}</email>

  8.   <msg>{{row.msg}}</msg>

  9. </f>

  10. {% endfor %}

  11. </feedbacks>

  12. </r>


Файл urls.py


urlpatterns = patterns('',

    (r'^send/', 'feedbacks.views.send'),

    (r'^feedbacks/', 'feedbacks.views.feedbacks'),

)

Модель базы данных


Опишем модель базы данных в файле "feedbacks/models.py"


  1. # -*- coding: utf-8 -*-

  2. # feedbacks/models.py

  3. from django.db import models

  4.  

  5. class Feedback(models.Model):

  6.     name = models.CharField(max_length=51, null=True)

  7.     email = models.CharField(max_length=51, null=True)

  8.     msg = models.CharField(max_length=5001, null=True)


* This source code was highlighted with Source Code Highlighter.

Обработчики запросов


И наконец создадим обработчики запросов в файле "feedbacks/views.py"


  1. # -*- coding: utf-8 -*-

  2. from django.views.generic.simple import direct_to_template

  3.  

  4. from models import Feedback

  5.  

  6. def send(request):

  7.     data = {'code' : 0}

  8.     name = request.REQUEST.get("name", "")

  9.     email = request.REQUEST.get("email", "")

  10.     msg = request.REQUEST.get("msg", "")

  11.     if (name=="") or (email=="") or (msg==""):

  12.         data['code'] = 1

  13.         data['msg'] = "Необходимо заполните все поля"

  14.     else:

  15.         f = Feedback(name=name, email=email, msg=msg)

  16.         f.save()

  17.     return direct_to_template(request, "feedback_result.xml", data, mimetype="text/xml")

  18.  

  19. def feedbacks(request):

  20.     data = {}    

  21.     data['feedbacks'] = Feedback.objects.all()        

  22.     return direct_to_template(request, "feedbacks.xml", data, mimetype="text/xml")


* This source code was highlighted with Source Code Highlighter.

Создадим структуру базы данных. Для этого выполним в каталоге проекта команду:

manage.py syncdb


После создания базы данных все готово для запуска сервера. Это можно сделать двумя способами: нажав в Aptana кнопку на панели инструментов Run или Ctrl+F11, либо выполнив в каталоге проекта команду:

manage.py runserver 8081

Проверка работоспособности сервера


Перейдем в браузере по ссылке: http://127.0.0.1:8081/send?name=name&email=email&msg=msg

Видим xml файл, значит наш сервер успешно обработал запрос.


  1. <r>

  2. <code>0</code>

  3. <msg></msg>

  4. </r>


Запускаем клиента на Flex и попробуем отправить сообщение через него.


post     post


Проверим что у нас накопилось в базе:

Перейдем в браузере по ссылке: http://127.0.0.1:8081/feedbacks


  1. <r>

  2. <feedbacks>

  3. <f>

  4.   <name>name</name>

  5.   <email>email</email>

  6.   <msg>msg</msg>

  7. </f>

  8. <f>

  9.   <name>Александр</name>

  10.   <email>alex@example.com</email>

  11.   <msg>Заработало!</msg>

  12. </f>

  13. </feedbacks>

  14. </r>


Все работает!

Для просмотра полученных сообщений http://127.0.0.1:8081/feedbacks можно сделать еще одно небольшое приложение Flex для администратора.

Заключение


Ну вот и все! Надеюсь кому-нибудь моя статья будет полезна. :)



Благодарю за внимание!


2 комментария:

  1. Огромное спасибо за статью! Собственно, на данный момент единственный пример в инете реализации обратной связи на флексе) Вопрос: возможно ли связаться с автором, что бы задать пару вопросов? Моменты простейшие, но вызывают крайний ступор, кучу времени убил, но так и не смог реализовать(

    ОтветитьУдалить
  2. Товарищи, кому не лень, можете скинуть рабочий пример обратной связи, который присылает сообщения введеные через форму на 9527665274@mail.ru к примеру...Никаких выкрутасов с графой, просто рабочий пример) Моя электронка 9527665274@mail.ru соответственно) Заранее огромное спасибо откликнувшимся!

    ОтветитьУдалить