Pep 8 standard is a good convention to use when coding especially when working as a team.Standards and conventions make reading other peoples code easier.Getting yourself to start adhere to these standards takes some time and effort, but by using the right tools it can take a shorter time.By the way, taking your time to learn these standards is quite worth the effort.
Pycharm is a wonderful python IDE which i would recommend to anybody doing development in python.Using pycharm you can set pep8 as an external tool, which you can invoke on any file you are currently working on to check whether it violates any standards.This can be done this way.
Install pep8 package from the python package index
pip install pep8
go to: File > Settings > External Tools > Add new
if your using virtual env, use the path to pep8 installed in the virtualenv's bin directory.Otherwise point it to the location where pep8 is installed, use the whereis command to find it.
Now add an output filter as follows.
You can now access the command from the tools menu or conveniently right click anywhere within the file currently being edited and select the command.
The output should be quite helpful in identifying changes which need to be made.
Wednesday, August 22, 2012
Monday, August 6, 2012
django factory boy - better test management
Django factory boy is an excellent replacement for fixtures, most of the time you will encounter problems with maintenance of fixtures.For instance if you do migrations often, the set of fixtures will become invalid and has to be edited to fit the new schema, this can be extremely painful if you have a complex schema and lots of data.
Factory boy makes it easy to create objects when you need them for tests.For example..
lets say you have this set of models,
Then your factories.py for these two will correspond to something like this
The tests for the factories themselves go something like this
Then your factories will go something like this.
Factory boy makes it easy to create objects when you need them for tests.For example..
lets say you have this set of models,
from django.db import models
class Owner(models.Model):
name = models.CharField(max_length=200)
phone = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Car(models.Model):
name = models.CharField(max_length=200)
owner = models.ForeignKey(Owner)
def __unicode__(self):
return self.name
Then your factories.py for these two will correspond to something like this
import factory
from models import Owner, Car
class OwnerFactory(factory.Factory):
FACTORY_FOR = Owner
name = 'bruce'
phone = '+254728037573'
class CarFactory(factory.Factory):
FACTORY_FOR = Car
name = 'jeep'
owner = factory.lazy_attribute(lambda a: OwnerFactory())
The tests for the factories themselves go something like this
from models import Car,Owner
from django.test.testcases import TestCase
class FactoryTestCase(TestCase):
def test_car_factory(self):
car = CarFactory()
self.assertTrue(isinstance(car, Car))
def test_owner_factory(self):
owner = OwnerFactory()
self.assertTrue(isinstance(owner, Owner))
Many to many fields are a bit tricky to emulate but this does the trick.
For instance lets say you have this set of models.
from django.db import models
class Pizza(models.Model):
name = models.CharField(max_length=120)
toppings = models.ManyToManyField(Topping)
def __unicode__(self):
return self.name
class Topping(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
Then your factories will go something like this.
from models import Pizza, Topping
import factory
class ToppingFactory(factory.Factory):
FACTORY_FOR = Topping
name = 'mushrooms'
class PizzaFactory(factory.Factory):
FACTORY_FOR = Pizza
name = 'mushroom delight'
@classmethod
def _prepare(cls, create, **kwargs):
topping = ToppingFactory()
pizza = super(PizzaFactory, cls)._prepare(create, **kwargs)
pizza.toppings.add(topping)
return pizza
So the key here is to override the _prepare method and assign the manytomanyfield objects here, since you have and instance of the object.
In conclusion factories are a good alternative to fixtures when used in the right way.
Thursday, April 12, 2012
building web applications
The best method to use when building web applications is to use frameworks.
Frameworks save on time and adhere to the principle of not repeating code
all the time (DRY).
So if you decide to use a framework, what should your choice be.There are many frameworks out there and therefore it would not be okay just to point you to one.To gain a deeper understanding of building web applications using frameworks it is advisable to go down the path of discovery.
Be patient
Nothing comes easy, everything requires time and effort, so don't expect to excel at it immediately.With continuous practice and diligent effort you will notice your skills and knowledge increasing.
I wish to stress the importance of persistence here.It's what will bear the results.
- Pick a framework based on any language you know of and learn it, this should be the beginning.
- After taking a week or two to learn the new framework, do a side project with it, not a serious one but something far from the basics.Try to implement some idea you've always had.
- Add the side project to your portfolio and start over again from step 1 this time with another framework which is related.
Be patient
Nothing comes easy, everything requires time and effort, so don't expect to excel at it immediately.With continuous practice and diligent effort you will notice your skills and knowledge increasing.
I wish to stress the importance of persistence here.It's what will bear the results.
Monday, April 9, 2012
Django Tastypie with android client part 2
This post picks up from part 1 where we had defined the api using tastypie.The purpose of this second part is to create an android client to consume the api.
here are the files that make up the android application.
RecipesActivity.java
package com.thecodachi.recipe;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.j256.ormlite.dao.Dao;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class RecipesActivity extends Activity {
public static String api_url = "http://10.0.2.2:8000/api/";
private List recipesList = null;
private ProgressDialog progDialog;
private ProgressThread progThread;
private ListView recipes;
private DatabaseHelper databaseHelper = null;
private ArrayAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
recipes = (ListView)findViewById(R.id.lvRecipes);
showDialog(0);
try{
//get our Dao and query for all customers in db
Dao recipes = getHelper().getRecipeDataDao();
recipesList = recipes.queryForAll();
}catch(SQLException e){
Log.e("LOG", "error getting products");
}
adapter = new ArrayAdapter(this,
R.layout.recipe_row,
R.id.recipeLabel,
recipesList);
recipes.setAdapter(adapter);
}
@Override
protected Dialog onCreateDialog(int id) {
switch(id){
case 0:
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progDialog.setMessage("Loading data...");
progThread = new ProgressThread();
progThread.start();
return progDialog;
default:
return null;
}
}
private class ProgressThread extends Thread{
private static final String LOG_TAG = "PROGRESS_THREAD";
@Override
public void run() {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(api_url+"recipes/?format=json&limit=0");
HttpResponse response = null;
try{
response = httpClient.execute(httpGet);
}catch(Exception e){
System.out.println(e.toString());
}
if(response!=null){
HttpEntity entity = response.getEntity();
String apiResponse = null;
try {
apiResponse = _getResponseBody(entity);
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(apiResponse!=null){
try{
Dao recipesDao = getHelper().getRecipeDataDao();
JsonElement json = new JsonParser().parse(apiResponse);
JsonObject rootObject = json.getAsJsonObject();
JsonArray array= rootObject.getAsJsonArray("objects");
Iterator iterator = array.iterator();
while(iterator.hasNext()){
JsonElement json2 = (JsonElement)iterator.next();
Gson gson = new Gson();
Recipe recipe = gson.fromJson(json2, Recipe.class);
recipesDao.createIfNotExists(recipe);
Log.d(LOG_TAG, "--------------------------------created recipe");
}
}catch(Exception e){
Log.e(LOG_TAG, "error creating recipe from json");
}
}
}
dismissDialog(0);
adapter.notifyDataSetChanged();
}
}
public static String _getResponseBody(final HttpEntity entity) throws IOException, ParseException {
if (entity == null) { throw new IllegalArgumentException("HTTP entity may not be null"); }
InputStream instream = entity.getContent();
if (instream == null) { return ""; }
if (entity.getContentLength() > Integer.MAX_VALUE) { throw new IllegalArgumentException(
"HTTP entity too large to be buffered in memory"); }
String charset = getContentCharSet(entity);
if (charset == null) {
charset = HTTP.DEFAULT_CONTENT_CHARSET;
}
Reader reader = new InputStreamReader(instream, charset);
StringBuilder buffer = new StringBuilder();
try {
char[] tmp = new char[1024];
int l;
while ((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
return buffer.toString();
}
public static String getContentCharSet(final HttpEntity entity) throws ParseException {
if (entity == null) { throw new IllegalArgumentException("HTTP entity may not be null"); }
String charset = null;
if (entity.getContentType() != null) {
HeaderElement values[] = entity.getContentType().getElements();
if (values.length > 0) {
NameValuePair param = values[0].getParameterByName("charset");
if (param != null) {
charset = param.getValue();
}
}
}
return charset;
}
private DatabaseHelper getHelper(){
if(databaseHelper == null){
databaseHelper = OpenHelperManager.getHelper(this, DatabaseHelper.class);
}
return databaseHelper;
}
}
Recipe.java class which defines a recipe object which can be persisted in the sqlite database using ormlite.
package com.thecodachi.recipe;
import com.j256.ormlite.field.DatabaseField;
public class Recipe {
@DatabaseField(id=true)
private int id;
@DatabaseField
private String name;
@DatabaseField
private String content;
Recipe(){
//used by ormlite
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return name;
}
}
DatabaseHelper.java responsible for persisting and retreiving objects from sqlite database using ormlite.
package com.thecodachi.recipe;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
//name of the database file for the application
private static final String DATABASE_NAME = "Recipe.db";
private static final int DATABASE_VERSION = 1;
/*
* the DAO objects we use to access the recipes*
*/
private Dao recipesDao = null;
public DatabaseHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
try{
Log.i(DatabaseHelper.class.getName(), "onCreate");
TableUtils.createTable(connectionSource, Recipe.class);
}catch(java.sql.SQLException e){
Log.e(DatabaseHelper.class.getName(),"can't create db");
throw new RuntimeException();
}
}
//called when your application is upgraded
@Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion,
int newVersion) {
try{
Log.i(DatabaseHelper.class.getName(), "onUpgrade");
TableUtils.dropTable(connectionSource, Recipe.class, true);
//after dropping old databases, we create the new ones
onCreate(db, connectionSource);
}catch(java.sql.SQLException e){
Log.e(DatabaseHelper.class.getName(), "can't drop databases");
throw new RuntimeException(e);
}
}
/* methods that returns the Database access object(Dao) for our product class
* will create it or just give the cached value
*/
public Dao getRecipeDataDao() throws java.sql.SQLException{
if(recipesDao == null){
recipesDao = getDao(Recipe.class);
}
return recipesDao;
}
/*
* close all database connections and clear any cached DAOs
*/
@Override
public void close(){
super.close();
recipesDao = null;
}
}
You can take a look at the rest of the resources belonging to this app from the repo which
i will share.
The implementation of the REST architecture i took in this example is not the best and it is
highly recommended not to use this approach when building an android application.The reason for
this is that the app does network requests within an activity.This should be done within a service
For a more detailed and recommended architecture for creating RESTful android application look here.
Otherwise this is just a demo.
Labels:
android,
database,
ormlite,
recipe,
REST,
rest protocol,
restful,
sqlite,
tastypie,
webservices
Sunday, March 25, 2012
Django Tastypie with android client
I've been using django-tastypie recently to create restful apis and i wanted to use it especially with an android client.
I've put together a sample application, django rest backend and an android client to demonstrate this.
So here is a quick walk through of the code.
Here is the models.py which describes a recipe.
from django.db import models
class Recipe(models.Model):
name = models.CharField(max_length=50)
content = models.TextField()
def __unicode__(self):
return self.name
We set up a Resource for our API using tastypie.
from tastypie.resources import ModelResource
from recipes.models import Recipe
class RecipeResource(ModelResource):
class Meta:
queryset = Recipe.objects.all()
resource_name = 'recipes'
allowed_methods = ['get']
include_resource_uri = False
def alter_list_data_to_serialize(self, request, data_dict):
if isinstance(data_dict, dict):
if 'meta' in data_dict:
#Get rid of the meta object
del(data_dict['meta'])
return data_dict
Now we set up the urlpattern to access the data
from django.conf.urls.defaults import patterns, include, url
from recipes.api.api import RecipeResource
from django.contrib import admin
admin.autodiscover()
recipe_resource = RecipeResource()
urlpatterns = patterns('',
url(r'^api/', include(recipe_resource.urls)),
url(r'^admin/', include(admin.site.urls)),
)
Test the api using curl.
$ curl -H 'Accept: application/json' http://localhost:8000/api/recipes/Now that the api works as expected the next part is to create an android app client to consume the api. This will be a simple app for viewing recipes.Later we will add the ability to add recipes to our recipe database from the android client. This will be covered in part 2 of this tutorial.
Labels:
android,
django,
git,
python,
REST,
rest protocol,
restful,
tastypie,
webservices
Thursday, March 15, 2012
It's okay to leave if things are not as expected
Lately i have been reading a series of articles about individuals who are leaving or have left their former places of employment and giving their reasons for leaving.It is very interesting to note that most express dislike about the way things were being steered by their former companies.What is being brought out is that these big companies had turned evil and deviated from their original well meaning motives, if they ever existed.
For one, i tend to think that this is natural.In the world there exists no organisation with an altruistic motive.To think of it, the golden rule is always "whats in it for me".What is actually happening is that eager graduates are drawn in to companies thinking that they are contributing to a greater good, only to realize this years later.Of course there's the usual bouts of philanthropy that usually exist, but deep down to the core, profit is the main motivation.
Startup founders are encouraged to formulate brilliant ideas by looking for problems to solve, or scratching common itches.Ones success is achieved, it all becomes about maximizing profits.Soon the users needs are swept aside.The outlook currently is that the future is in startups, but remember too that the big corporations which have turned evil were once startups.Inevitably as a startup grows into a large company, moral decay starts occuring.This comes with size and does not occur within a close tightly knit community around a startup because everybody knows everybody and there is close interaction.
There exists a theory in the field of Organization management that brings out this aspect, that as an organization grows it becomes more and more unstable.so it's expected.
Saturday, March 10, 2012
Data access on android made easy with OrmLite
OrmLite is a wonderful Object Relational Mapper available for the android operating system.
If your using the normal methods to access the sqlite database, then you are bound to find the
process very tedious.I realized i needed an orm when i found myself writing redundant code and it came to my attention that i was actually writing my own orm.
OrmLite is suited for android because it is lightweight and therefore easy to import to an android project.
Furthermore it uses java annotations to mark classes to be persisted which make your code look clean and easier to understand.
public class Customer { @DatabaseField int id; @DatabaseField String name; @DatabaseField String country; @DatabaseField String phone; @DatabaseField String address; @DatabaseField String businessName; Customer(){ //used by ormlite } @Override public String toString(){ return this.name; } }
Data access is done using Daos(Data access Object),these offer convenient
methods for querying, creating, deleting... objects on the sqlite database
If your using the normal methods to access the sqlite database, then you are bound to find the
process very tedious.I realized i needed an orm when i found myself writing redundant code and it came to my attention that i was actually writing my own orm.
OrmLite is suited for android because it is lightweight and therefore easy to import to an android project.
Furthermore it uses java annotations to mark classes to be persisted which make your code look clean and easier to understand.
import com.j256.ormlite.field.DatabaseField;
public class Customer { @DatabaseField int id; @DatabaseField String name; @DatabaseField String country; @DatabaseField String phone; @DatabaseField String address; @DatabaseField String businessName; Customer(){ //used by ormlite } @Override public String toString(){ return this.name; } }
To create a table we use TableUtils' createTable method
TableUtils.createTable(connectionSource, Customer.class);
private Dao<Customer, Integer> customersDao = getDao(Customer.class);customersDao.create(customer); customersDao.delete(customer); customersDao.queryForAll(); In conclusion, using ormlite saves more time and is more convenient.
Subscribe to:
Posts (Atom)

