Feeds:
Posts
Comments

Posts Tagged ‘PyAMF’

Jus trying to figure out passing the auth parameters (username, password) from flex client to django backend using pyamf, it turn around to be simple to just pass parameters instead of a class object, Here is the code.

1. In the gateway.py add the following

# Try to use Django User model and methods
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User

pyamf.register_class(User, 'com.example.model.UserVO')

def userLogin(request, username=None, password=None):
        user = authenticate(username=username, password=password)
        if user is not None:
                login(request, user)
                return user
        return None

def userLogout(request):
        logout(request)
        return True

gw = DjangoGateway({
        "UserService.userLogin": userLogin,
        "UserService.userLogout": userLogout,
})

2. In the mxml, here it goes.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import com.atlife.model.UserVO;
			import mx.utils.ArrayUtil;
			import mx.controls.Alert;
			
			[Bindable] private var loginData:UserVO
			private var connection:NetConnection;
			private var gateway:String = "http://localhost:8000/gateway/";
			
			private function init():void
			{
				connection = new NetConnection();
				connection.connect(gateway);
			}
			
			private function loginUser():void
			{
				connection.call("UserService.userLogin", 
                                     new Responder(onResult, onFault), txt_username.text, txt_password.text);
			}
			
			private function onResult(data:Object):void
			{
				if (data != null)
				{
					loginData = data as UserVO;
					welcomeUser.text = "Hi " + loginData.username;
					logout.visible = true;
				} else {
					welcomeUser.text = "Entered wrong username or password";
					logout.visible = false;
				}
				clearUser();
			}
			
			private function onLogout():void
			{
				if (loginData != null)
				{
					connection.call("UserService.userLogout", 
                                                  new Responder(onResult_logout, onFault));	
				}
			}
			
			private function onResult_logout(data:Object):void
			{
				if (data == true)
				{
					welcomeUser.text = loginData.username + " logout successfully";
					logout.visible = false;
					loginData = new UserVO();
					clearUser();
				}
			}
			private function onFault(data:Object):void
			{
				trace(data);
			}
			
			private function clearUser():void
			{
				txt_username.text = "";
				txt_password.text = "";
			}

		]]>
	</mx:Script>
	<mx:VBox width="100%" height="100%">
	<mx:Text id="welcomeUser" textAlign="center" width="100%" fontSize="18" color="red" />
	<mx:VDividedBox width="100%" height="100%">
		
	<mx:Button id="logout" visible="false" label="Logout" click="onLogout()"/>
	<mx:Panel title="User Login" width="100%" height="100%" layout="horizontal" cornerRadius="10">
		<mx:Form width="100%" height="100%" cornerRadius="10">
			<mx:FormHeading label="Enter Details" />
				<mx:FormItem label="User Name: " width="100%" required="true">
						<mx:TextInput id="txt_username" text=""  width="100%" />
				</mx:FormItem>
				<mx:FormItem label="Password: " width="100%" required="true">
						<mx:TextInput id="txt_password"  width="100%"  displayAsPassword="true"/>
						
				</mx:FormItem>
				<mx:FormItem label="" direction="horizontal" width="100%">
						<mx:Button label="Clear" click="clearUser()" />
						<mx:Button label="Login" click="loginUser()" />
				</mx:FormItem>
		</mx:Form>
	</mx:Panel>
	</mx:VDividedBox>
	</mx:VBox>
</mx:WindowedApplication>

3. The UserVO model object can be used to in the validate user objects in the later stage.

package com.example.model
{
	[RemoteClass(alias="com.example.model.UserVO")]
	
	[Bindable]
	public class UserVO
	{
		//Most of the variable won't be required, possibly can use it for future, 
		//make sure to use correct data types
		public var id:int;
		public var username:String;
		public var password:String;
		public var email:String;
		public var first_name:String;
		public var last_name:String;
		public var date_joined:String;
		public var groups:String;
		public var is_active:Boolean;
		public var is_staff:Boolean;
		public var is_superuser:Boolean;
		public var last_login:String;
		public var user_permissions:String;
		public var backend:String; 
	}
}

Read Full Post »

Simple Django, PyAMF, Flex Example

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()

Read Full Post »