Coverage for family/models.py: 99%
215 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 19:26 +0800
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 19:26 +0800
1from django.db import models
2from django.contrib.auth.models import User
3from django.urls import reverse
4from pgvector.django import VectorField
7class Person(models.Model):
8 """Family members and important individuals"""
9 GENDER_CHOICES = [
10 ('M', 'Male'),
11 ('F', 'Female'),
12 ('O', 'Other'),
13 ]
15 name = models.CharField(max_length=100)
16 birth_date = models.DateField(null=True, blank=True)
17 death_date = models.DateField(null=True, blank=True)
18 gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
19 bio = models.TextField(blank=True)
20 photo = models.ImageField(upload_to='people/', blank=True)
21 email = models.EmailField(blank=True)
22 phone = models.CharField(max_length=20, blank=True)
24 created_at = models.DateTimeField(auto_now_add=True)
25 updated_at = models.DateTimeField(auto_now=True)
27 class Meta:
28 ordering = ['name']
30 def __str__(self):
31 return self.name
34class Location(models.Model):
35 """Geographic information and places"""
36 LOCATION_TYPES = [
37 ('home', 'Home'),
38 ('work', 'Work'),
39 ('school', 'School'),
40 ('hospital', 'Hospital'),
41 ('travel', 'Travel'),
42 ('other', 'Other'),
43 ]
45 name = models.CharField(max_length=200)
46 address = models.TextField(blank=True)
47 latitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
48 longitude = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
49 location_type = models.CharField(max_length=20, choices=LOCATION_TYPES, default='other')
50 description = models.TextField(blank=True)
52 created_at = models.DateTimeField(auto_now_add=True)
54 def __str__(self):
55 return self.name
58class Institution(models.Model):
59 """External organizations"""
60 INSTITUTION_TYPES = [
61 ('hospital', 'Hospital'),
62 ('school', 'School'),
63 ('company', 'Company'),
64 ('government', 'Government'),
65 ('religious', 'Religious'),
66 ('restaurant', 'Restaurant'),
67 ('entertainment', 'Entertainment'),
68 ('other', 'Other'),
69 ]
71 name = models.CharField(max_length=200)
72 institution_type = models.CharField(max_length=20, choices=INSTITUTION_TYPES)
73 website = models.URLField(blank=True)
74 phone = models.CharField(max_length=20, blank=True)
75 email = models.EmailField(blank=True)
76 address = models.TextField(blank=True)
77 established_date = models.DateField(null=True, blank=True)
78 description = models.TextField(blank=True)
80 created_at = models.DateTimeField(auto_now_add=True)
82 def __str__(self):
83 return self.name
86class Event(models.Model):
87 """Important milestones and activities"""
88 EVENT_TYPES = [
89 ('birthday', 'Birthday'),
90 ('wedding', 'Wedding'),
91 ('graduation', 'Graduation'),
92 ('funeral', 'Funeral'),
93 ('reunion', 'Family Reunion'),
94 ('holiday', 'Holiday'),
95 ('milestone', 'Milestone'),
96 ('other', 'Other'),
97 ]
99 name = models.CharField(max_length=200)
100 description = models.TextField(blank=True)
101 event_type = models.CharField(max_length=20, choices=EVENT_TYPES)
102 start_date = models.DateTimeField()
103 end_date = models.DateTimeField(null=True, blank=True)
104 location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True)
105 institution = models.ForeignKey(Institution, on_delete=models.SET_NULL, null=True, blank=True)
107 # Many-to-many relationships
108 participants = models.ManyToManyField(Person, related_name='events', blank=True)
110 created_at = models.DateTimeField(auto_now_add=True)
111 updated_at = models.DateTimeField(auto_now=True)
113 # AI Integration fields
114 content_embedding = VectorField(dimensions=1536, null=True, blank=True)
115 embedding_updated = models.DateTimeField(null=True, blank=True)
117 class Meta:
118 ordering = ['-start_date']
120 def __str__(self):
121 return f"{self.name} ({self.start_date.year})"
124class Story(models.Model):
125 """Family memories, anecdotes, and experiences"""
126 STORY_TYPES = [
127 ('memory', 'Memory'),
128 ('legend', 'Family Legend'),
129 ('experience', 'Life Experience'),
130 ('wisdom', 'Wisdom'),
131 ('tradition', 'Tradition'),
132 ('other', 'Other'),
133 ]
135 title = models.CharField(max_length=200)
136 content = models.TextField()
137 story_type = models.CharField(max_length=20, choices=STORY_TYPES, default='memory')
138 date_occurred = models.DateField(null=True, blank=True)
139 location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True)
141 # Many-to-many relationships
142 people = models.ManyToManyField(Person, related_name='stories', blank=True)
143 events = models.ManyToManyField(Event, related_name='stories', blank=True)
145 created_at = models.DateTimeField(auto_now_add=True)
146 updated_at = models.DateTimeField(auto_now=True)
148 # AI Integration fields
149 content_embedding = VectorField(dimensions=1536, null=True, blank=True)
150 embedding_updated = models.DateTimeField(null=True, blank=True)
152 class Meta:
153 ordering = ['-created_at']
154 verbose_name_plural = "Stories"
156 def __str__(self):
157 return self.title
160class Multimedia(models.Model):
161 """Photos, videos, documents, audio files"""
162 MEDIA_TYPES = [
163 ('photo', 'Photo'),
164 ('video', 'Video'),
165 ('audio', 'Audio'),
166 ('document', 'Document'),
167 ('other', 'Other'),
168 ]
170 title = models.CharField(max_length=200)
171 description = models.TextField(blank=True)
172 media_type = models.CharField(max_length=20, choices=MEDIA_TYPES)
173 file = models.FileField(upload_to='media/')
174 file_size = models.PositiveIntegerField(null=True, blank=True)
175 created_date = models.DateTimeField(null=True, blank=True)
176 location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True)
178 # Many-to-many relationships
179 people = models.ManyToManyField(Person, related_name='media', blank=True)
180 events = models.ManyToManyField(Event, related_name='media', blank=True)
181 stories = models.ManyToManyField(Story, related_name='media', blank=True)
183 created_at = models.DateTimeField(auto_now_add=True)
184 updated_at = models.DateTimeField(auto_now=True)
186 class Meta:
187 ordering = ['-created_at']
188 verbose_name_plural = "Multimedia"
190 def __str__(self):
191 return self.title
194class Relationship(models.Model):
195 """Network of relationships between people"""
196 RELATIONSHIP_TYPES = [
197 ('parent', 'Parent'),
198 ('child', 'Child'),
199 ('spouse', 'Spouse'),
200 ('sibling', 'Sibling'),
201 ('grandparent', 'Grandparent'),
202 ('grandchild', 'Grandchild'),
203 ('friend', 'Friend'),
204 ('colleague', 'Colleague'),
205 ('other', 'Other'),
206 ]
208 person_from = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='relationships_from')
209 person_to = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='relationships_to')
210 relationship_type = models.CharField(max_length=20, choices=RELATIONSHIP_TYPES)
211 start_date = models.DateField(null=True, blank=True)
212 end_date = models.DateField(null=True, blank=True)
213 description = models.TextField(blank=True)
215 created_at = models.DateTimeField(auto_now_add=True)
217 class Meta:
218 unique_together = ['person_from', 'person_to', 'relationship_type']
220 def __str__(self):
221 return f"{self.person_from} -> {self.person_to} ({self.relationship_type})"
224class Health(models.Model):
225 """Personal and family health records"""
226 RECORD_TYPES = [
227 ('checkup', 'Medical Checkup'),
228 ('illness', 'Illness'),
229 ('medication', 'Medication'),
230 ('surgery', 'Surgery'),
231 ('allergy', 'Allergy'),
232 ('genetic', 'Genetic Condition'),
233 ('other', 'Other'),
234 ]
236 person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='health_records')
237 record_type = models.CharField(max_length=20, choices=RECORD_TYPES)
238 title = models.CharField(max_length=200)
239 description = models.TextField()
240 date = models.DateField()
241 doctor = models.CharField(max_length=100, blank=True)
242 institution = models.ForeignKey(Institution, on_delete=models.SET_NULL, null=True, blank=True)
243 is_hereditary = models.BooleanField(default=False)
245 created_at = models.DateTimeField(auto_now_add=True)
247 # AI Integration fields
248 content_embedding = VectorField(dimensions=1536, null=True, blank=True)
249 embedding_updated = models.DateTimeField(null=True, blank=True)
251 class Meta:
252 ordering = ['-date']
254 def __str__(self):
255 return f"{self.person.name} - {self.title}"
258class Heritage(models.Model):
259 """Family values, traditions, and wisdom"""
260 HERITAGE_TYPES = [
261 ('values', 'Family Values'),
262 ('tradition', 'Tradition'),
263 ('wisdom', 'Wisdom'),
264 ('skill', 'Skill'),
265 ('recipe', 'Recipe'),
266 ('other', 'Other'),
267 ]
269 IMPORTANCE_LEVELS = [
270 (1, 'Low'),
271 (2, 'Medium'),
272 (3, 'High'),
273 (4, 'Critical'),
274 ]
276 title = models.CharField(max_length=200)
277 heritage_type = models.CharField(max_length=20, choices=HERITAGE_TYPES)
278 description = models.TextField()
279 origin_person = models.ForeignKey(Person, on_delete=models.SET_NULL, null=True, related_name='heritage_originated')
280 inheritors = models.ManyToManyField(Person, related_name='heritage_inherited', blank=True)
281 importance = models.IntegerField(choices=IMPORTANCE_LEVELS, default=2)
283 # Relationships
284 stories = models.ManyToManyField(Story, related_name='heritage', blank=True)
285 events = models.ManyToManyField(Event, related_name='heritage', blank=True)
287 created_at = models.DateTimeField(auto_now_add=True)
289 # AI Integration fields
290 content_embedding = VectorField(dimensions=1536, null=True, blank=True)
291 embedding_updated = models.DateTimeField(null=True, blank=True)
293 def __str__(self):
294 return self.title
297class Planning(models.Model):
298 """Future goals and family vision"""
299 TIME_RANGES = [
300 ('short', 'Short-term (< 1 year)'),
301 ('medium', 'Medium-term (1-5 years)'),
302 ('long', 'Long-term (> 5 years)'),
303 ]
305 PRIORITY_LEVELS = [
306 (1, 'Low'),
307 (2, 'Medium'),
308 (3, 'High'),
309 (4, 'Critical'),
310 ]
312 STATUS_CHOICES = [
313 ('planned', 'Planned'),
314 ('in_progress', 'In Progress'),
315 ('completed', 'Completed'),
316 ('cancelled', 'Cancelled'),
317 ]
319 title = models.CharField(max_length=200)
320 description = models.TextField()
321 time_range = models.CharField(max_length=10, choices=TIME_RANGES)
322 priority = models.IntegerField(choices=PRIORITY_LEVELS, default=2)
323 status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='planned')
324 target_date = models.DateField(null=True, blank=True)
325 expected_outcome = models.TextField(blank=True)
327 # Relationships
328 involved_people = models.ManyToManyField(Person, related_name='plans', blank=True)
330 created_at = models.DateTimeField(auto_now_add=True)
331 updated_at = models.DateTimeField(auto_now=True)
333 def __str__(self):
334 return self.title
337class Career(models.Model):
338 """Work and education history"""
339 CAREER_TYPES = [
340 ('education', 'Education'),
341 ('work', 'Work'),
342 ('volunteer', 'Volunteer'),
343 ('internship', 'Internship'),
344 ('other', 'Other'),
345 ]
347 person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name='career_history')
348 career_type = models.CharField(max_length=20, choices=CAREER_TYPES)
349 title = models.CharField(max_length=200)
350 institution = models.ForeignKey(Institution, on_delete=models.SET_NULL, null=True, blank=True)
351 start_date = models.DateField()
352 end_date = models.DateField(null=True, blank=True)
353 description = models.TextField(blank=True)
354 achievements = models.TextField(blank=True)
355 salary_range = models.CharField(max_length=50, blank=True)
357 # Relationships
358 events = models.ManyToManyField(Event, related_name='careers', blank=True)
360 created_at = models.DateTimeField(auto_now_add=True)
362 class Meta:
363 ordering = ['-start_date']
365 def __str__(self):
366 return f"{self.person.name} - {self.title}"
369class Assets(models.Model):
370 """Important property and documents"""
371 ASSET_TYPES = [
372 ('property', 'Real Estate'),
373 ('vehicle', 'Vehicle'),
374 ('jewelry', 'Jewelry'),
375 ('insurance', 'Insurance'),
376 ('investment', 'Investment'),
377 ('document', 'Important Document'),
378 ('other', 'Other'),
379 ]
381 LEGAL_STATUS = [
382 ('owned', 'Owned'),
383 ('leased', 'Leased'),
384 ('shared', 'Shared Ownership'),
385 ('trust', 'In Trust'),
386 ('other', 'Other'),
387 ]
389 name = models.CharField(max_length=200)
390 asset_type = models.CharField(max_length=20, choices=ASSET_TYPES)
391 description = models.TextField(blank=True)
392 estimated_value = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
393 acquisition_date = models.DateField(null=True, blank=True)
394 location = models.CharField(max_length=200, blank=True)
395 legal_status = models.CharField(max_length=20, choices=LEGAL_STATUS, default='owned')
396 importance = models.IntegerField(choices=[(1, 'Low'), (2, 'Medium'), (3, 'High'), (4, 'Critical')], default=2)
398 # Relationships
399 owners = models.ManyToManyField(Person, related_name='assets')
400 related_documents = models.ManyToManyField(Multimedia, related_name='assets', blank=True)
401 plans = models.ManyToManyField(Planning, related_name='assets', blank=True)
403 created_at = models.DateTimeField(auto_now_add=True)
404 updated_at = models.DateTimeField(auto_now=True)
406 class Meta:
407 verbose_name_plural = "Assets"
409 def __str__(self):
410 return self.name
413class Timeline(models.Model):
414 """Time-based organization of information"""
415 TIMELINE_TYPES = [
416 ('personal', 'Personal Milestone'),
417 ('family', 'Family Event'),
418 ('historical', 'Historical Context'),
419 ('other', 'Other'),
420 ]
422 title = models.CharField(max_length=200)
423 description = models.TextField(blank=True)
424 timeline_type = models.CharField(max_length=20, choices=TIMELINE_TYPES)
425 date = models.DateField()
426 end_date = models.DateField(null=True, blank=True)
427 importance = models.IntegerField(choices=[(1, 'Low'), (2, 'Medium'), (3, 'High'), (4, 'Critical')], default=2)
428 historical_context = models.TextField(blank=True)
430 # Relationships (generic foreign keys could be used here for more flexibility)
431 people = models.ManyToManyField(Person, related_name='timeline_entries', blank=True)
432 events = models.ManyToManyField(Event, related_name='timeline_entries', blank=True)
433 stories = models.ManyToManyField(Story, related_name='timeline_entries', blank=True)
435 created_at = models.DateTimeField(auto_now_add=True)
437 class Meta:
438 ordering = ['-date']
440 def __str__(self):
441 return f"{self.title} ({self.date})"