Interacting with SugarCRM from Python

We recently tackled a change in Customer Relationship Management (CRM) software here at Brooks.  Being a software shop, having some sort of programmatic access to our records was a must.  We investigated several options and ultimately settled on SugarCRM.  Versions 6 and 7 both support a SOAP via REST API that exposes considerable functionality to any programming language that can handle HTTP requests.  There was even a wrapper library for python, one of our go-to languages.  Bingo!

When we first starting using this library we identified several ... inefficiencies ... that were producing a considerable amount of initial load time, overhead, and redundancy.  We've since addressed those issues and, as a result of our contributions, had the library's maintenance turned over to our team.  Our improvements include delayed instantiation, additional query options, multi-relate support, and single-request multi-field retrieval.  What follows is a brief introduction to using the library to interact with SugarCRM from Python, providing a rich interface for customization or automation.

The first step is establishing a SugarCRM session, like so:

from sugarcrm.sugarcrm import Sugarcrm

url = 'http://<yoursugarserver>/service/v4_1/rest.php'
user = 'admin' // or a user's username
pwd = '<supersecurepass>' # or getpass() to let the user log in
conn = Sugarcrm(url, user, pwd)

With a connection established, retrieving records is surprisingly easy:

users = conn['Contacts'].search('Daniel Casper')

This accesses the Contacts module and searches for a specific value. The library returns a list of entries that match the criteria (or an empty list if none match). Working through the returned records is done using standard python iteration:

for user in users:
    print user['first_name', 'last_name']

Worth noting here is the tuple-based access to fields on a SugarEntry. The library has been designed to reduce the number of HTTP requests by allowing multiple fields to be retrieved at the same time. A single field (user['first_name']) will still work, but if you need to access many fields it will be considerably faster to retrieve them all at once, rather than sending individual requests.

Modifying fields on a record is also straight forward:

user['phone_work'] = '208-523-6970'
user.save()

When saving, the request isn't sent until save() is called. Making all your changes before saving (as opposed to saving after each change) will reduce overhead.

Finally, what good would a CRM be without the ability to relate records to each other?

brooks = conn['Accounts'].search('Brooks Internet Software')[0] # We know this only returns 1 record.
dan = conn['Contacts'].search('Daniel Casper')[0] # Again, single record.
brooks.relate(dan)

This will create a relationship between the two records that can be viewed from the standard SugarCRM web interface.

That wraps up the introduction to the functionality exposed by the library. Additional features, like field-specific queries, multiple record relation, custom relationship types, retrieval of related records, and others will be described in follow-up posts.