Last two weeks, i was trying to figure how to work with Django + PyAMF with Flex front end. Seems to be not enough examples for new users. Finally i got an example from amfphp – “Flex Contacts” to start with, and bit of changes made flex to interact with django backend thru pyamf.
Let’s start from django.
1. models.py (Usual django model declaration)
class Contact(models.Model):
contact_fname = models.CharField(max_length=100)
contact_lname = models.CharField(max_length=100)
contact_email = models.CharField(max_length=100)
contact_url = models.CharField(max_length=100)
class Meta:
ordering = ["contact_fname"]
verbose_name = "Contact"
verbose_name_plural = "Contact's"
def __unicode__(self):
return self.contact_fname
After doing changes to model.py, make sure to run “python manage.py syncdb” to create contact table in the database.
2. Create a file “gateway.py” under your project_name/app_name/
#import the required pyamf and django modules from pyamf.remoting.gateway.django import DjangoGateway import pyamf from django.core.exceptions import ObjectDoesNotExist # import your model from app_name.models import Contact # need to register your django models to provide alias (mapping) # to Flex models pyamf.register_class(Contact, 'com.example.model.ContactVO') # To get all Contacts def getContacts(request): return Contact.objects.all() # To update and create a new contact, the create/update from flex # would be return as class object. so it can be save/update directly # Please check for pyamf.register_class def saveContact(request, data): try: obj = Contact.objects.get(id=data.id) data.save() except ObjectDoesNotExist: obj = Contact(contact_fname=data.contact_fname, contact_lname=data.contact_lname, contact_email=data.contact_email, contact_url=data.contact_url) obj.save() return obj.id # To remove a contact, get the contact id from flex def removeContact(request, id): try: obj = Contact.objects.get(id=id) obj.delete() except ObjectDoesNotExist: pass return id # Finally to expose django views use DjangoGateway gw = DjangoGateway({ "ContactService.getContacts": getContacts, "ContactService.saveContact": saveContact, "ContactService.removeContact": removeContact })3. Add the following lines in url.py
from app_name import gateway # add in the urlpatterns (r'^gateway/$', gateway.gw),4. To start django development server, run “python manage.py runserver”.
5. To check the pyamf connection, create a python_test.py and add the following.
# pyamf has RemotingService act as a client for AMF calls from pyamf.remoting.client import RemotingService gw = RemotingService('http://127.0.0.1:8000/gateway/') #To get service proxy for ContactService, which is defined in the gateway.py service = gw.getService('ContactService') # To check the objects available in the model print service.getContacts()6. Run "python python_test.py" to get the output.
The flex code was taken from http://jonniespratley.com/ with minor changes to fit with this example, Thanks to the author for easier example to start with flex.
7. Create a flex project - FlexContact and here is the FlexContact.mxml<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" width="1024" height="768" creationComplete="init()"> <mx:Script> <![CDATA[ import com.example.model.ContactVO; import mx.collections.ArrayCollection; import mx.utils.ArrayUtil; import mx.controls.Alert; [Bindable] private var contactCollection:ArrayCollection; [Bindable] private var selectedContact:ContactVO; private var connection:NetConnection; private var gateway:String = "http://localhost:8000/gateway/"; private function init():void { connection = new NetConnection(); connection.connect(gateway); getContacts(); } //Load this function every action like create/update/remove, so that it gets all the contacts private function getContacts():void { connection.call("ContactService.getContacts", new Responder(onResult_contacts, onFault)); } //Create a new contact or update selected contact private function saveContact():void { if (selectedContact == null) { //Create a new Contact var newContact:ContactVO = new ContactVO(); newContact.id = 0; newContact.contact_fname = txt_fname.text; newContact.contact_lname = txt_lname.text; newContact.contact_email = txt_email.text; newContact.contact_url = txt_url.text; connection.call("ContactService.saveContact", new Responder( onResult, onFault), newContact); clearContact(); } else { var updateContact:ContactVO = new ContactVO(); updateContact.id = selectedContact.id; updateContact.contact_fname = txt_fname.text; updateContact.contact_lname = txt_lname.text; updateContact.contact_email = txt_email.text; updateContact.contact_url = txt_url.text; connection.call("ContactService.saveContact", new Responder( onResult, onFault), updateContact); clearContact(); } } private function clearContact():void { selectedContact = new ContactVO(); dg_contacts.selectedItem = null; txt_fname.text = ""; txt_lname.text = ""; txt_email.text = ""; txt_url.text = ""; } private function selectHandler(event:Event):void { selectedContact = event.target.selectedItem as ContactVO; } private function removeContact():void { if (selectedContact != null) { connection.call("ContactService.removeContact", new Responder( onResult, onFault ), selectedContact.id ); } } private function onResult_contacts(data:Object):void { contactCollection = new ArrayCollection( ArrayUtil.toArray(data) ); } private function onFault(data:Object):void { Alert.show( "Service Error" ); } private function onResult(data:Object):void { getContacts(); } ]]> </mx:Script> <mx:VBox width="100%" height="100%"> <mx:ApplicationControlBar width="100%"> <mx:Label text="Flex Contact Manager" fontSize="18" fontWeight="bold" /> <mx:Spacer width="100%" /> <mx:Button label="Refresh" click="getContacts()" /> <mx:Button label="Remove" click="removeContact()" /> </mx:ApplicationControlBar> <mx:HDividedBox width="100%" height="100%"> <mx:Panel title="Contact Details" width="100%" height="100%" layout="horizontal" cornerRadius="10"> <mx:Form width="100%" height="100%" cornerRadius="10"> <mx:FormHeading label="Contact Information" /> <mx:FormItem label="ID:" width="100%"> <mx:Label text="{selectedContact.id}" /> </mx:FormItem> <mx:FormItem label="First Name: " width="100%" required="true"> <mx:TextInput id="txt_fname" text="{selectedContact.contact_fname}" width="100%" /> </mx:FormItem> <mx:FormItem label="Last Name: " width="100%" required="true"> <mx:TextInput id="txt_lname" text="{selectedContact.contact_lname}" width="100%" /> </mx:FormItem> <mx:FormItem label="Email : " width="100%" required="true"> <mx:TextInput id="txt_email" text="{selectedContact.contact_email}" width="100%" /> </mx:FormItem> <mx:FormItem label="URL: " width="100%" required="true"> <mx:TextInput id="txt_url" text="{selectedContact.contact_url}" width="100%" /> </mx:FormItem> <mx:FormItem label="" direction="horizontal" width="100%"> <mx:Button label="Clear" click="clearContact()" /> <mx:Button label="Save" click="saveContact()" /> </mx:FormItem> </mx:Form> </mx:Panel> <mx:Panel title="Contacts" width="100%" height="100%" layout="vertical" alpha="1.0"> <mx:DataGrid id="dg_contacts" width="100%" height="100%" change="selectHandler(event)" dataProvider="{contactCollection}"> <mx:columns> <mx:DataGridColumn headerText="ID" dataField="id" width="50" /> <mx:DataGridColumn headerText="First Name" dataField="contact_fname" /> <mx:DataGridColumn headerText="Last" dataField="contact_lname" /> <mx:DataGridColumn headerText="Email" dataField="contact_email" /> <mx:DataGridColumn headerText="URL" dataField="contact_url" /> </mx:columns> </mx:DataGrid> </mx:Panel> </mx:HDividedBox> </mx:VBox> </mx:WindowedApplication>8. The Contact Model was defined as
package com.example.model { [RemoteClass(alias="com.example.model.ContactVO")] [Bindable] public class ContactVO { public var id:int; public var contact_fname:String; public var contact_lname:String; public var contact_email:String; public var contact_url:String; } }9. Make sure to start the django development server, Hopefully the application has to work after flex compilation.print service.getContacts()
Useful examples.
Couple of points though..
You need not have set verbose_name and verbose_name_plural options.
Also the plural of “Contact” is not “Contact’s”. It’s “Contacts”. See http://apostrophe.me/ for the correct use of apostrophes.
Cheers!
Great post. Really helped my while exploring some ideas.