Files
booking_backend/marketing/models.py
2026-04-10 20:51:43 -05:00

68 lines
2.6 KiB
Python

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})"