from django.conf import settings from django.db import models from django.db.models import Q class ListingClick(models.Model): """Server-side record of a public listing detail view with optional UTM / ad parameters.""" class ListingType(models.TextChoices): EQUIPMENT = "equipment", "Equipment" ADVENTURE = "adventure", "Adventure" class TrafficType(models.TextChoices): ORGANIC = "organic", "Organic" MARKETING = "marketing", "Marketing" vendor = models.ForeignKey("accounts.VendorProfile", on_delete=models.CASCADE, related_name="listing_clicks") listing_type = models.CharField(max_length=16, choices=ListingType.choices) equipment_item = models.ForeignKey( "equipment.EquipmentItem", on_delete=models.CASCADE, null=True, blank=True, related_name="marketing_clicks", ) adventure_offering = models.ForeignKey( "adventrues.AdventureOffering", on_delete=models.CASCADE, null=True, blank=True, related_name="marketing_clicks", ) traffic_type = models.CharField(max_length=16, choices=TrafficType.choices) utm_source = models.CharField(max_length=255, blank=True) utm_medium = models.CharField(max_length=255, blank=True) utm_campaign = models.CharField(max_length=255, blank=True) utm_term = models.CharField(max_length=255, blank=True) utm_content = models.CharField(max_length=255, blank=True) gclid = models.CharField(max_length=255, blank=True) fbclid = models.CharField(max_length=255, blank=True) referrer = models.TextField(blank=True) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="listing_clicks", ) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ("-created_at",) indexes = [ models.Index(fields=["vendor", "created_at"]), models.Index(fields=["vendor", "traffic_type", "created_at"]), models.Index(fields=["utm_campaign", "created_at"]), ] constraints = [ models.CheckConstraint( condition=Q(listing_type="equipment", equipment_item__isnull=False, adventure_offering__isnull=True) | Q(listing_type="adventure", equipment_item__isnull=True, adventure_offering__isnull=False), name="listing_click_exactly_one_listing", ), ] def __str__(self) -> str: return f"ListingClick #{self.pk} ({self.listing_type}, {self.traffic_type})"