import logging from rest_framework import serializers logger = logging.getLogger(__name__) class VibnAttributionCaptureMixin: """ A Django REST Framework ViewSet/APIView mixin that automatically extracts marketing attribution fields (UTMs, referrer) from incoming request payloads or HTTP headers and binds them to the saving object. Compatible with any Django REST Framework serializer. """ def extract_attribution_data(self, request): """ Extracts UTM and referrer keys from request data, falling back to request headers if required. """ # Try request payload first data = request.data or {} utm_source = data.get("utm_source") utm_medium = data.get("utm_medium") utm_campaign = data.get("utm_campaign") utm_content = data.get("utm_content") utm_term = data.get("utm_term") # Capture Referrer from payload or fallback to HTTP headers referrer = data.get("referrer") if not referrer: referrer = request.META.get("HTTP_REFERER") return { "utm_source": utm_source, "utm_medium": utm_medium, "utm_campaign": utm_campaign, "utm_content": utm_content, "utm_term": utm_term, "referrer": referrer, } def perform_create(self, serializer): """ In DRF ViewSets, overrides perform_create to automatically inject attribution fields directly into the saved model instance. """ attrib_data = self.extract_attribution_data(self.request) # Save serializer with attribution params injected as overrides instance = serializer.save( **{k: v for k, v in attrib_data.items() if v is not None} ) logger.info( f"VibnTracker: Saved attribution data to {instance.__class__.__name__} " f"(Source: {attrib_data['utm_source']}, Campaign: {attrib_data['utm_campaign']})" ) return instance