Package: django-basecrm
Django BasecrmA Django app that connects to theBaseCRM API(v2)This package is now Python3 only, and supports Django 1.11 and above. For previous versions please refer to the Python2 branch.A lightweight Django app to wrap therequestslibrary and provide easy endpoints for the BaseCRM API.Note that this is not acompleteclient SDK; it’s a helper app that has the functionality we needed. Contributions gratefully accepted.Theutilsmodule provides arequest()method that allows less config-heavy calls to the BaseCRM API, relying on settings while still allowing all options to be passed and/or overridden, both forrequestsand for the API endpoint itself. There are also helpers toparse()andcount()the results (parsestrips the metadata, whilecountreturns the server-side count pre pagination).Thehelpersmodule also provides some higher level methods for interacting with thecontacts,deals,pipelineandstagesendpoints (and the top level__init__module exposes these). There’s also a setting for retrieving and caching the stages for a pipeline (only 1 supported currently).FeaturesLow configuration overhead, so it’s easy to call API methods from anywhere in your codePre-submission validation forCREATEandUPDATEcalls will raise catchable custom exceptionsFlexible serializers make creating BaseCRM objects from Django ORM objects trivialCurrent LimitationsOnly a single pipeline is currently supported.Stages and pipelines are, by default, cached at the app level (in memory), with no cachebusting method exposed.NoDELETEcalls are implementedCREATEandUPDATEare only implemented oncontactsanddealsendpointsGETis only implemented forcontacts,deals,notes,pipelinesandstagesSerializers are only used one-way; they do not deserializeProbably many others…InstallationYou can install Django-BaseCRM from PyPI with…:pip install --upgrade django-basecrmSetupAt a minimum, you will need to add the following to yoursettings.py:BASECRM_API_URL='https://api.getbase.com/v2/'
BASECRM_API_KEY=xxxx
BASECRM_INSTANTIATE_ON_START=False # If this is set to True, the pipeline ID and stage IDs will be retrieved when the app is started for the first time, and then held in memory…putting your own API key instead ofxxx, obv. Note that the API url is fully qualified, includingthe protocolandtrailing slash.You’ll also need to add this app to yourINSTALLED_APPS; it doesn’t really matter where (in terms of ordering)::INSTALLED_APPS = [
    ...
    'django_basecrm',
    ...
]Next, you’ll probably want to extend the serializers to cater for your models.For example, let’s imagine you have an app calledpeoplethat contains a your customUserprofile model calledPerson, that represents the contacts you want to track in Base.Let’s also imagine that your model has an attribute forinfo, a@propertyforphoneand a OneToOne relationship withUser.Createpeople/serializers.pyand paste the following code:from django_basecrm import get_contacts, create_contact
from django_basecrm.serializers import ContactModelSerializer

class PersonSerializer(ContactModelSerializer):
    is_organization = False
    description = 'info'

    def get_email(self, obj):
        return obj.user.email

    class Meta:
        model = 'people.Person'Things to note:We’re extendingContactModelSerializer; there’s also aDealModelSerializerthat behaves identically but is set for thedealendpoint’s fieldsWe set theis_organizationfield toFalseexplicitly; assuming your model doesn’t have a field (or property) with the same name, this will never be automatically overridden.Thedescriptionfield is set to get the value of your object’sinfofield at runtimeThephonefield will similarly get the value of your object’sphoneproperty at runtime; we don’t need to specify it as the fields are identically namedTheemailfield, although not explicitly defined, will be populated by the return value of theget_emailmethod. Anyget_*method will always take priority in setting the serializer value for the related field.TheMeta.modelattribute is set to a string,contianing both the app_name and the model_name– any other string format will fail. It is however possible to specify a class directly (e.g.model = Person).Note that you can also specifyfieldsas an attribute to the Meta subclass; this will override the serializer’s list of fieldsOnce you’ve got this far, you really only need to call the functions, perhaps creating a module within yourpeopleapp to offercreate_person_from_objectmethods and the like.An exampleget_or_createfunction for a BaseCRM contact, using the above models and serializers, might look like::def get_or_create_person(person_id):
    person = Person.objects.get(pk=person_id)
    base_contacts = django_basecrm.get_contacts(email=person.user.email))
    if len(base_contacts) > 1:
        # This shouldn't happen if we enforce email uniqueness in Django
        raise Exception()
    elif len(base_contacts) == 1:
        base_contact = base_contacts[0]
    else:
        serialized_person = PersonSerializer(person) # This is the serializer we defined above
        base_contact = django_basecrm.create_contact(serialized_person.to_dict())
    return base_contactContributeContributions are very welcome. Please fork and submit pull requests, with all code covered by unit tests as per the existing code.