| 21 | |
| 22 | |
| 23 | class Person(models.Model): |
| 24 | @property |
| 25 | def distinct_ids(self) -> List[str]: |
| 26 | if hasattr(self, "distinct_ids_cache"): |
| 27 | return [id.distinct_id for id in self.distinct_ids_cache] # type: ignore |
| 28 | return [ |
| 29 | id[0] |
| 30 | for id in PersonDistinctId.objects.filter(person=self, team_id=self.team_id) |
| 31 | .order_by("id") |
| 32 | .values_list("distinct_id") |
| 33 | ] |
| 34 | |
| 35 | # :DEPRECATED: This should happen through the plugin server |
| 36 | def add_distinct_id(self, distinct_id: str) -> None: |
| 37 | PersonDistinctId.objects.create(person=self, distinct_id=distinct_id, team_id=self.team_id) |
| 38 | |
| 39 | # :DEPRECATED: This should happen through the plugin server |
| 40 | def _add_distinct_ids(self, distinct_ids: List[str]) -> None: |
| 41 | for distinct_id in distinct_ids: |
| 42 | self.add_distinct_id(distinct_id) |
| 43 | |
| 44 | def split_person(self, main_distinct_id: Optional[str]): |
| 45 | distinct_ids = Person.objects.get(pk=self.pk).distinct_ids |
| 46 | if not main_distinct_id: |
| 47 | self.properties = {} |
| 48 | self.save() |
| 49 | main_distinct_id = distinct_ids[0] |
| 50 | |
| 51 | for distinct_id in distinct_ids: |
| 52 | if not distinct_id == main_distinct_id: |
| 53 | with transaction.atomic(): |
| 54 | pdi = PersonDistinctId.objects.select_for_update().get(person=self, distinct_id=distinct_id) |
| 55 | person = Person.objects.create(team_id=self.team_id) |
| 56 | pdi.person_id = str(person.id) |
| 57 | pdi.version = (pdi.version or 0) + 1 |
| 58 | pdi.save(update_fields=["version", "person_id"]) |
| 59 | |
| 60 | from posthog.models.person.util import create_person, create_person_distinct_id |
| 61 | |
| 62 | create_person_distinct_id( |
| 63 | team_id=self.team_id, |
| 64 | distinct_id=distinct_id, |
| 65 | person_id=str(person.uuid), |
| 66 | is_deleted=False, |
| 67 | version=pdi.version, |
| 68 | ) |
| 69 | create_person(team_id=self.team_id, uuid=str(person.uuid), version=person.version or 0) |
| 70 | |
| 71 | objects = PersonManager() |
| 72 | created_at: models.DateTimeField = models.DateTimeField(auto_now_add=True, blank=True) |
| 73 | |
| 74 | # used to prevent race conditions with set and set_once |
| 75 | properties_last_updated_at: models.JSONField = models.JSONField(default=dict, null=True, blank=True) |
| 76 | |
| 77 | # used for evaluating if we need to override the value or not (value: set or set_once) |
| 78 | properties_last_operation: models.JSONField = models.JSONField(null=True, blank=True) |
| 79 | |
| 80 | team: models.ForeignKey = models.ForeignKey("Team", on_delete=models.CASCADE) |
searching dependent graphs…