Template
Extract always-on public/portal/UTM plus optional email_sms, directmail, blog, payments, social, and social_ai so new client sites can be bootstrapped from this seed. Refs #1 Refs #2 Co-authored-by: Cursor <cursoragent@cursor.com>
53 lines
1.8 KiB
Python
53 lines
1.8 KiB
Python
from django.db import models
|
|
|
|
from core.models import TimeStampedModel, UUIDPrimaryKeyModel
|
|
from leads.models import Lead
|
|
|
|
|
|
class PageView(UUIDPrimaryKeyModel, TimeStampedModel):
|
|
"""One successful GET of a public marketing page."""
|
|
|
|
path = models.CharField(max_length=512, db_index=True)
|
|
|
|
class Meta:
|
|
ordering = ["-created_at"]
|
|
indexes = [
|
|
models.Index(fields=["created_at", "path"]),
|
|
]
|
|
|
|
def __str__(self) -> str:
|
|
return self.path or "/"
|
|
|
|
|
|
class UTMVisit(UUIDPrimaryKeyModel, TimeStampedModel):
|
|
correlation_id = models.CharField(max_length=64, db_index=True)
|
|
path = models.CharField(max_length=512, blank=True)
|
|
referrer = models.URLField(blank=True, max_length=1024)
|
|
utm_source = models.CharField(max_length=128, blank=True)
|
|
utm_medium = models.CharField(max_length=128, blank=True)
|
|
utm_campaign = models.CharField(max_length=128, blank=True)
|
|
utm_term = models.CharField(max_length=128, blank=True)
|
|
utm_content = models.CharField(max_length=128, blank=True)
|
|
user_agent = models.CharField(max_length=512, blank=True)
|
|
|
|
class Meta:
|
|
ordering = ["-created_at"]
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.utm_source or 'direct'} / {self.path}"
|
|
|
|
|
|
class Attribution(TimeStampedModel):
|
|
lead = models.OneToOneField(
|
|
Lead, on_delete=models.CASCADE, related_name="attribution"
|
|
)
|
|
visit = models.ForeignKey(
|
|
UTMVisit, null=True, blank=True, on_delete=models.SET_NULL
|
|
)
|
|
utm_source = models.CharField(max_length=128, blank=True)
|
|
utm_medium = models.CharField(max_length=128, blank=True)
|
|
utm_campaign = models.CharField(max_length=128, blank=True)
|
|
|
|
def __str__(self) -> str:
|
|
return f"attr {self.lead_id} ← {self.utm_source or 'direct'}"
|