feat(家庭成员): 添加家庭成员模型并关联感悟和计划
添加家庭成员模型(FamilyMember)并关联到感悟记录(InsightRecord)和今日计划(TodayPlan) 修改相关表单、视图和模板以支持发言人功能 添加数据库迁移文件和初始化脚本 更新报告模板显示发言人信息
This commit is contained in:
@@ -6,7 +6,8 @@ from .models import (
|
|||||||
InsightRecord,
|
InsightRecord,
|
||||||
FamilyTask,
|
FamilyTask,
|
||||||
TodayPlan,
|
TodayPlan,
|
||||||
SystemConfig
|
SystemConfig,
|
||||||
|
FamilyMember
|
||||||
)
|
)
|
||||||
|
|
||||||
class ReadingRecordForm(forms.ModelForm):
|
class ReadingRecordForm(forms.ModelForm):
|
||||||
@@ -27,8 +28,9 @@ class InsightRecordForm(forms.ModelForm):
|
|||||||
"""感悟记录表单"""
|
"""感悟记录表单"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InsightRecord
|
model = InsightRecord
|
||||||
fields = ['content', 'file']
|
fields = ['speaker', 'content', 'file']
|
||||||
widgets = {
|
widgets = {
|
||||||
|
'speaker': forms.Select(attrs={'class': 'form-select'}),
|
||||||
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': '请输入感悟'}),
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5, 'placeholder': '请输入感悟'}),
|
||||||
'file': forms.FileInput(attrs={'class': 'form-control'}),
|
'file': forms.FileInput(attrs={'class': 'form-control'}),
|
||||||
}
|
}
|
||||||
@@ -50,9 +52,10 @@ class TodayPlanForm(forms.ModelForm):
|
|||||||
"""今日计划表单"""
|
"""今日计划表单"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TodayPlan
|
model = TodayPlan
|
||||||
fields = ['date', 'content', 'priority', 'type', 'status']
|
fields = ['date', 'speaker', 'content', 'priority', 'type', 'status']
|
||||||
widgets = {
|
widgets = {
|
||||||
'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
||||||
|
'speaker': forms.Select(attrs={'class': 'form-select'}),
|
||||||
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': '请输入计划内容'}),
|
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': '请输入计划内容'}),
|
||||||
'priority': forms.Select(attrs={'class': 'form-select'}),
|
'priority': forms.Select(attrs={'class': 'form-select'}),
|
||||||
'type': forms.Select(attrs={'class': 'form-select'}),
|
'type': forms.Select(attrs={'class': 'form-select'}),
|
||||||
|
|||||||
38
core/migrations/0005_initial_speaker.py
Normal file
38
core/migrations/0005_initial_speaker.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 5.1.4
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0004_systemconfig_sender_email'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FamilyMember',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=20, unique=True, verbose_name='姓名')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': '家庭成员',
|
||||||
|
'verbose_name_plural': '家庭成员',
|
||||||
|
'ordering': ['name'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='insightrecord',
|
||||||
|
name='speaker',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.familymember', verbose_name='发言人'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='todayplan',
|
||||||
|
name='speaker',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='core.familymember', verbose_name='发言人'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -71,6 +71,20 @@ class PlanType(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
class FamilyMember(models.Model):
|
||||||
|
"""家庭成员"""
|
||||||
|
name = models.CharField(max_length=20, unique=True, verbose_name="姓名")
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||||||
|
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "家庭成员"
|
||||||
|
verbose_name_plural = "家庭成员"
|
||||||
|
ordering = ['name']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
class ReadingRecord(models.Model):
|
class ReadingRecord(models.Model):
|
||||||
"""阅读记录表"""
|
"""阅读记录表"""
|
||||||
date = models.DateField(default=timezone.now, verbose_name="日期")
|
date = models.DateField(default=timezone.now, verbose_name="日期")
|
||||||
@@ -95,6 +109,7 @@ class InsightRecord(models.Model):
|
|||||||
"""感悟记录表"""
|
"""感悟记录表"""
|
||||||
date = models.DateField(default=timezone.now, verbose_name="日期")
|
date = models.DateField(default=timezone.now, verbose_name="日期")
|
||||||
content = models.TextField(verbose_name="内容")
|
content = models.TextField(verbose_name="内容")
|
||||||
|
speaker = models.ForeignKey(FamilyMember, on_delete=models.CASCADE, verbose_name="发言人")
|
||||||
file = models.FileField(upload_to='insight_files/', blank=True, null=True, verbose_name="上传文件")
|
file = models.FileField(upload_to='insight_files/', blank=True, null=True, verbose_name="上传文件")
|
||||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
|
||||||
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
||||||
@@ -129,6 +144,7 @@ class TodayPlan(models.Model):
|
|||||||
"""今日计划表"""
|
"""今日计划表"""
|
||||||
date = models.DateField(default=timezone.now, verbose_name="日期")
|
date = models.DateField(default=timezone.now, verbose_name="日期")
|
||||||
content = models.TextField(verbose_name="内容")
|
content = models.TextField(verbose_name="内容")
|
||||||
|
speaker = models.ForeignKey(FamilyMember, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="发言人")
|
||||||
priority = models.ForeignKey(Priority, on_delete=models.CASCADE, default=2, verbose_name="优先级")
|
priority = models.ForeignKey(Priority, on_delete=models.CASCADE, default=2, verbose_name="优先级")
|
||||||
type = models.ForeignKey(PlanType, on_delete=models.CASCADE, default=4, verbose_name="类型")
|
type = models.ForeignKey(PlanType, on_delete=models.CASCADE, default=4, verbose_name="类型")
|
||||||
status = models.ForeignKey(Status, on_delete=models.CASCADE, default=1, verbose_name="状态")
|
status = models.ForeignKey(Status, on_delete=models.CASCADE, default=1, verbose_name="状态")
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
{% if yesterday_insight %}
|
{% if yesterday_insight %}
|
||||||
<ul>
|
<ul>
|
||||||
{% for insight in yesterday_insight %}
|
{% for insight in yesterday_insight %}
|
||||||
<li>{{ insight.content }}</li>
|
<li><strong>{{ insight.speaker.name }}:</strong>{{ insight.content }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -148,6 +148,7 @@
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>发言人</th>
|
||||||
<th>类型</th>
|
<th>类型</th>
|
||||||
<th>内容</th>
|
<th>内容</th>
|
||||||
<th>优先级</th>
|
<th>优先级</th>
|
||||||
@@ -157,6 +158,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for plan in today_plan %}
|
{% for plan in today_plan %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>{{ plan.speaker.name }}</td>
|
||||||
<td>{{ plan.get_type_display }}</td>
|
<td>{{ plan.get_type_display }}</td>
|
||||||
<td>{{ plan.content }}</td>
|
<td>{{ plan.content }}</td>
|
||||||
<td>{{ plan.get_priority_display }}</td>
|
<td>{{ plan.get_priority_display }}</td>
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ from .models import (
|
|||||||
InsightRecord,
|
InsightRecord,
|
||||||
FamilyTask,
|
FamilyTask,
|
||||||
TodayPlan,
|
TodayPlan,
|
||||||
SystemConfig
|
SystemConfig,
|
||||||
|
FamilyMember
|
||||||
)
|
)
|
||||||
from .forms import (
|
from .forms import (
|
||||||
ReadingRecordForm,
|
ReadingRecordForm,
|
||||||
@@ -147,6 +148,7 @@ def delete_reading(request, pk):
|
|||||||
# 添加感悟记录
|
# 添加感悟记录
|
||||||
def add_insight(request):
|
def add_insight(request):
|
||||||
"""添加感悟记录"""
|
"""添加感悟记录"""
|
||||||
|
family_members = FamilyMember.objects.all()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = InsightRecordForm(request.POST, request.FILES)
|
form = InsightRecordForm(request.POST, request.FILES)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -158,13 +160,14 @@ def add_insight(request):
|
|||||||
else:
|
else:
|
||||||
form = InsightRecordForm()
|
form = InsightRecordForm()
|
||||||
|
|
||||||
context = {'form': form}
|
context = {'form': form, 'family_members': family_members}
|
||||||
return render(request, 'core/add_insight.html', context)
|
return render(request, 'core/add_insight.html', context)
|
||||||
|
|
||||||
# 编辑感悟记录
|
# 编辑感悟记录
|
||||||
def edit_insight(request, pk):
|
def edit_insight(request, pk):
|
||||||
"""编辑感悟记录"""
|
"""编辑感悟记录"""
|
||||||
insight = get_object_or_404(InsightRecord, pk=pk)
|
insight = get_object_or_404(InsightRecord, pk=pk)
|
||||||
|
family_members = FamilyMember.objects.all()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = InsightRecordForm(request.POST, request.FILES, instance=insight)
|
form = InsightRecordForm(request.POST, request.FILES, instance=insight)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -174,7 +177,7 @@ def edit_insight(request, pk):
|
|||||||
else:
|
else:
|
||||||
form = InsightRecordForm(instance=insight)
|
form = InsightRecordForm(instance=insight)
|
||||||
|
|
||||||
context = {'form': form, 'insight': insight}
|
context = {'form': form, 'insight': insight, 'family_members': family_members}
|
||||||
return render(request, 'core/edit_insight.html', context)
|
return render(request, 'core/edit_insight.html', context)
|
||||||
|
|
||||||
# 删除感悟记录
|
# 删除感悟记录
|
||||||
@@ -257,6 +260,7 @@ def delete_today_reading(request, pk):
|
|||||||
# 添加今日感悟记录
|
# 添加今日感悟记录
|
||||||
def add_today_insight(request):
|
def add_today_insight(request):
|
||||||
"""添加今日感悟记录"""
|
"""添加今日感悟记录"""
|
||||||
|
family_members = FamilyMember.objects.all()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = InsightRecordForm(request.POST, request.FILES)
|
form = InsightRecordForm(request.POST, request.FILES)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -268,13 +272,14 @@ def add_today_insight(request):
|
|||||||
else:
|
else:
|
||||||
form = InsightRecordForm()
|
form = InsightRecordForm()
|
||||||
|
|
||||||
context = {'form': form}
|
context = {'form': form, 'family_members': family_members}
|
||||||
return render(request, 'core/add_insight.html', context)
|
return render(request, 'core/add_insight.html', context)
|
||||||
|
|
||||||
# 编辑今日感悟记录
|
# 编辑今日感悟记录
|
||||||
def edit_today_insight(request, pk):
|
def edit_today_insight(request, pk):
|
||||||
"""编辑今日感悟记录"""
|
"""编辑今日感悟记录"""
|
||||||
insight = get_object_or_404(InsightRecord, pk=pk)
|
insight = get_object_or_404(InsightRecord, pk=pk)
|
||||||
|
family_members = FamilyMember.objects.all()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = InsightRecordForm(request.POST, request.FILES, instance=insight)
|
form = InsightRecordForm(request.POST, request.FILES, instance=insight)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -284,7 +289,7 @@ def edit_today_insight(request, pk):
|
|||||||
else:
|
else:
|
||||||
form = InsightRecordForm(instance=insight)
|
form = InsightRecordForm(instance=insight)
|
||||||
|
|
||||||
context = {'form': form, 'insight': insight}
|
context = {'form': form, 'insight': insight, 'family_members': family_members}
|
||||||
return render(request, 'core/edit_insight.html', context)
|
return render(request, 'core/edit_insight.html', context)
|
||||||
|
|
||||||
# 删除今日感悟记录
|
# 删除今日感悟记录
|
||||||
@@ -373,6 +378,7 @@ def today_plan(request):
|
|||||||
# 添加今日计划
|
# 添加今日计划
|
||||||
def add_today_plan(request):
|
def add_today_plan(request):
|
||||||
"""添加今日计划"""
|
"""添加今日计划"""
|
||||||
|
family_members = FamilyMember.objects.all()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = TodayPlanForm(request.POST)
|
form = TodayPlanForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -382,13 +388,14 @@ def add_today_plan(request):
|
|||||||
else:
|
else:
|
||||||
form = TodayPlanForm()
|
form = TodayPlanForm()
|
||||||
|
|
||||||
context = {'form': form}
|
context = {'form': form, 'family_members': family_members}
|
||||||
return render(request, 'core/add_today_plan.html', context)
|
return render(request, 'core/add_today_plan.html', context)
|
||||||
|
|
||||||
# 编辑今日计划
|
# 编辑今日计划
|
||||||
def edit_today_plan(request, pk):
|
def edit_today_plan(request, pk):
|
||||||
"""编辑今日计划"""
|
"""编辑今日计划"""
|
||||||
plan = get_object_or_404(TodayPlan, pk=pk)
|
plan = get_object_or_404(TodayPlan, pk=pk)
|
||||||
|
family_members = FamilyMember.objects.all()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = TodayPlanForm(request.POST, instance=plan)
|
form = TodayPlanForm(request.POST, instance=plan)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -398,7 +405,7 @@ def edit_today_plan(request, pk):
|
|||||||
else:
|
else:
|
||||||
form = TodayPlanForm(instance=plan)
|
form = TodayPlanForm(instance=plan)
|
||||||
|
|
||||||
context = {'form': form, 'plan': plan}
|
context = {'form': form, 'plan': plan, 'family_members': family_members}
|
||||||
return render(request, 'core/edit_today_plan.html', context)
|
return render(request, 'core/edit_today_plan.html', context)
|
||||||
|
|
||||||
# 删除今日计划
|
# 删除今日计划
|
||||||
|
|||||||
22
update_db.py
Normal file
22
update_db.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import sqlite3
|
||||||
|
|
||||||
|
conn = sqlite3.connect('db.sqlite3')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO core_familymember (name, created_at, updated_at)
|
||||||
|
VALUES ('默认成员', datetime('now', 'localtime'), datetime('now', 'localtime'));
|
||||||
|
''')
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
ALTER TABLE core_insightrecord ADD COLUMN speaker_id INTEGER NOT NULL DEFAULT 1;
|
||||||
|
''')
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
ALTER TABLE core_todayplan ADD COLUMN speaker_id INTEGER NOT NULL DEFAULT 1;
|
||||||
|
''')
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
print("Database updated successfully!")
|
||||||
10
verify_db.py
Normal file
10
verify_db.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import sqlite3
|
||||||
|
conn = sqlite3.connect('db.sqlite3')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'core_%' ORDER BY name;")
|
||||||
|
print("Tables:", [r[0] for r in cursor.fetchall()])
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM core_familymember;")
|
||||||
|
print("Family members count:", cursor.fetchone()[0])
|
||||||
|
cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='core_insightrecord';")
|
||||||
|
print("InsightRecord schema:", cursor.fetchone()[0])
|
||||||
|
conn.close()
|
||||||
Reference in New Issue
Block a user