A minimal Django 4+ package for customer acquisition pipeline management. Track leads, manage contacts, automate outreach campaigns, and handle customer onboarding.
- Lead Management - Track potential customers through your acquisition pipeline
- Contact Management - Multiple contacts per lead (decision makers, influencers, etc.)
- Touchpoint Tracking - Record all outreach (calls, emails, SMS, meetings)
- Outreach Campaigns - Automated multi-step sequences with email/SMS
- Marketing Documents - Manage brochures, case studies, proposals
- Seller Profiles - Internal profiles for automation preferences
- Onboarding Handoff - Convert leads to customers with callbacks
pip install django-acquisitionsWith optional dependencies:
# With Celery support for async tasks
pip install django-acquisitions[celery]
# With Twilio for SMS
pip install django-acquisitions[twilio]
# With Django REST Framework for API
pip install django-acquisitions[drf]
# All optional dependencies
pip install django-acquisitions[all]- Add to
INSTALLED_APPS:
INSTALLED_APPS = [
# ...
'acquisitions',
]- Run migrations:
python manage.py migrate acquisitions- Configure settings (optional):
# settings.py
# For multi-tenant (MST-style with django-organizations)
ACQUISITIONS_TENANT_MODEL = 'accounts.Account'
# For schema-per-tenant (MFT-style with django-tenants)
ACQUISITIONS_TENANT_MODEL = None # Uses schema isolation
# Communication backends
ACQUISITIONS_EMAIL_BACKEND = 'acquisitions.backends.email.django_email.DjangoEmailBackend'
ACQUISITIONS_SMS_BACKEND = 'acquisitions.backends.sms.twilio.TwilioBackend'
# Twilio settings (if using Twilio backend)
TWILIO_ACCOUNT_SID = 'your-account-sid'
TWILIO_AUTH_TOKEN = 'your-auth-token'
TWILIO_FROM_NUMBER = '+1234567890'
# Celery settings
ACQUISITIONS_USE_CELERY = True
# Onboarding callback (called when lead converts to customer)
ACQUISITIONS_ONBOARDING_CALLBACK = 'myapp.services.create_customer_from_lead'The core model representing a potential customer:
from acquisitions.models import Lead
lead = Lead.objects.create(
company_name='Acme Corp',
email='contact@acme.com',
status=Lead.Status.NEW,
source=Lead.Source.WEBSITE,
)Multiple contacts per lead:
from acquisitions.models import LeadContact
contact = LeadContact.objects.create(
lead=lead,
first_name='John',
last_name='Doe',
title='VP of Operations',
role=LeadContact.Role.DECISION_MAKER,
email='john@acme.com',
is_primary=True,
)Track all interactions:
from acquisitions.models import Touchpoint
from django.utils import timezone
touchpoint = Touchpoint.objects.create(
lead=lead,
touchpoint_type=Touchpoint.TouchpointType.EMAIL,
direction=Touchpoint.Direction.OUTBOUND,
subject='Introduction to our services',
occurred_at=timezone.now(),
performed_by_id=request.user.id,
)Automated sequences:
from acquisitions.models import OutreachCampaign, CampaignStep
campaign = OutreachCampaign.objects.create(
name='New Lead Nurture',
status=OutreachCampaign.Status.ACTIVE,
)
CampaignStep.objects.create(
campaign=campaign,
step_order=1,
step_type=CampaignStep.StepType.EMAIL,
delay_days=0,
subject_template='Welcome to {{ company_name }}!',
body_template='Hi {{ contact.first_name }}, ...',
)When using with Django REST Framework:
# urls.py
from django.urls import path, include
urlpatterns = [
path('api/acquisitions/', include('acquisitions.api.urls')),
]Available endpoints:
GET/POST /api/acquisitions/leads/- List/create leadsGET/PUT/DELETE /api/acquisitions/leads/{uuid}/- Lead detailPOST /api/acquisitions/leads/{uuid}/convert/- Convert to customerPOST /api/acquisitions/leads/{uuid}/enroll_campaign/- Enroll in campaignGET/POST /api/acquisitions/leads/{uuid}/contacts/- Lead contactsGET/POST /api/acquisitions/leads/{uuid}/touchpoints/- Lead touchpointsGET/POST /api/acquisitions/campaigns/- Outreach campaignsGET/POST /api/acquisitions/documents/- Marketing documents
django-acquisitions supports multi-tenancy out of the box with two approaches:
For django-tenants with PostgreSQL schema isolation:
# settings.py
SHARED_APPS = [
'django_tenants',
'django.contrib.contenttypes',
'django.contrib.auth',
# ... other shared apps
]
TENANT_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'acquisitions', # Include in tenant apps
# ... other tenant-specific apps
]
INSTALLED_APPS = SHARED_APPS + [app for app in TENANT_APPS if app not in SHARED_APPS]
# Leave ACQUISITIONS_TENANT_MODEL unset (defaults to None)
# Schema isolation handles tenant separation automaticallyRun migrations for each tenant as per django-tenants documentation.
For shared-schema multi-tenancy with a foreign key to your tenant/account model:
# settings.py
ACQUISITIONS_TENANT_MODEL = 'accounts.Account' # Your tenant model
ACQUISITIONS_TENANT_FIELD_NAME = 'account' # FK field name (default)Then use the TenantFilterMixin in your views:
from acquisitions.mixins import TenantFilterMixin
from acquisitions.models import ProspectiveClient
class ProspectiveClientListView(TenantFilterMixin, ListView):
model = ProspectiveClient
def get_queryset(self):
return self.filter_by_tenant(super().get_queryset())The mixin automatically detects tenants from request.tenant (django-tenants) or request.user.account.
For automated outreach, add to your Celery beat schedule:
# celery.py or settings.py
CELERY_BEAT_SCHEDULE = {
'process_acquisitions_outreach': {
'task': 'acquisitions.tasks.outreach_tasks.process_scheduled_outreach',
'schedule': crontab(minute='*/5'), # Every 5 minutes
},
}Use abstract models to add custom fields:
# myapp/models.py
from acquisitions.abstract_models import AbstractLead
from myapp.models import Account
class Lead(AbstractLead):
account = models.ForeignKey(Account, on_delete=models.CASCADE)
custom_field = models.CharField(max_length=100)
class Meta(AbstractLead.Meta):
abstract = FalseThen configure:
ACQUISITIONS_LEAD_MODEL = 'myapp.Lead'BSD-3-Clause