Coverage for family/admin_views.py: 100%
41 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
1"""
2Custom admin views and context processors for Family Knowledge Management System
3"""
5from django.contrib import admin
6from django.db.models import Count
7from django.utils import timezone
8from datetime import timedelta
9from .models import Person, Story, Event, Multimedia, Timeline
12def get_family_dashboard_context():
13 """
14 Generate context data for the family dashboard
15 """
16 try:
17 # Family statistics
18 family_stats = {
19 'person_count': Person.objects.count(),
20 'story_count': Story.objects.count(),
21 'event_count': Event.objects.count(),
22 'multimedia_count': Multimedia.objects.count(),
23 }
25 # Recent activities (last 30 days)
26 thirty_days_ago = timezone.now() - timedelta(days=30)
28 recent_activities = []
30 # Recent stories
31 recent_stories = Story.objects.filter(
32 created_at__gte=thirty_days_ago
33 ).order_by('-created_at')[:3]
35 for story in recent_stories:
36 recent_activities.append({
37 'icon': '📖',
38 'title': f'新故事: {story.title[:30]}...' if len(story.title) > 30 else f'新故事: {story.title}',
39 'time': story.created_at.strftime('%m月%d日'),
40 'url': f'/admin/family/story/{story.id}/change/',
41 })
43 # Recent people
44 recent_people = Person.objects.filter(
45 created_at__gte=thirty_days_ago
46 ).order_by('-created_at')[:2]
48 for person in recent_people:
49 recent_activities.append({
50 'icon': '👥',
51 'title': f'新成员: {person.name}',
52 'time': person.created_at.strftime('%m月%d日'),
53 'url': f'/admin/family/person/{person.id}/change/',
54 })
56 # Recent multimedia
57 recent_media = Multimedia.objects.filter(
58 uploaded_at__gte=thirty_days_ago
59 ).order_by('-uploaded_at')[:2]
61 for media in recent_media:
62 recent_activities.append({
63 'icon': '📸',
64 'title': f'新照片: {media.title or "未命名"}',
65 'time': media.uploaded_at.strftime('%m月%d日'),
66 'url': f'/admin/family/multimedia/{media.id}/change/',
67 })
69 # Sort by time (most recent first)
70 recent_activities.sort(key=lambda x: x['time'], reverse=True)
71 recent_activities = recent_activities[:5] # Limit to 5 items
73 # Upcoming events (next 60 days)
74 upcoming_date = timezone.now() + timedelta(days=60)
75 upcoming_events = Event.objects.filter(
76 date__gte=timezone.now().date(),
77 date__lte=upcoming_date.date()
78 ).order_by('date')[:5]
80 return {
81 'family_stats': family_stats,
82 'recent_activities': recent_activities,
83 'upcoming_events': upcoming_events,
84 }
86 except Exception as e:
87 # Fallback in case of any errors
88 return {
89 'family_stats': {
90 'person_count': 0,
91 'story_count': 0,
92 'event_count': 0,
93 'multimedia_count': 0,
94 },
95 'recent_activities': [],
96 'upcoming_events': [],
97 }
100class FamilyAdminSite(admin.AdminSite):
101 """
102 Custom admin site with family-specific customizations
103 """
104 site_header = '家族知识管理系统'
105 site_title = '家族知识管理'
106 index_title = '欢迎来到家族知识管理系统'
108 def index(self, request, extra_context=None):
109 """
110 Override the admin index to include family dashboard data
111 """
112 if extra_context is None:
113 extra_context = {}
115 # Add family dashboard context
116 dashboard_context = get_family_dashboard_context()
117 extra_context.update(dashboard_context)
119 return super().index(request, extra_context)
122# Create custom admin site instance
123family_admin_site = FamilyAdminSite(name='family_admin')
126def family_dashboard_context_processor(request):
127 """
128 Context processor to provide family dashboard data to templates
129 """
130 if request.path.startswith('/admin/'):
131 return get_family_dashboard_context()
132 return {}