feat: 新增Snippet全局内容模型(TeamMember/Testimonial/Partner/NavigationMenu/SiteSettings)
- 新增 apps.core.TeamMember/Testimonial/Partner:简单 register_snippet,含 order 排序字段
- 新增 apps.core.NavigationMenu+NavigationMenuItem:ClusterableModel+Orderable+InlinePanel,
支持内部页面或外部链接二选一
- 新增 apps.core.SiteSettings:接入 wagtail.contrib.settings + BaseSiteSetting,
存放公司信息/ICP备案号/社交账号等全局配置
- 新增只读 API:/api/v1/custom/core/{team,testimonials,partners,navigation,site-settings}/
- 补充 apps/core/tests.py 单元测试,pytest 用例由 11 个增至 24 个,全部通过
- 更新设计文档 §2.16 Phase 1 进度清单
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# Generated by Django 6.0.5 on 2026-08-07 03:14
|
||||
|
||||
import django.db.models.deletion
|
||||
import modelcluster.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
('wagtailcore', '0097_baselogentry_uuid_action_timestamp_indexes'),
|
||||
('wagtailimages', '0027_image_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NavigationMenu',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(help_text='前端按此标识获取菜单,如 main(主导航)、footer(页脚导航)', max_length=50, unique=True, verbose_name='菜单标识')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '导航菜单',
|
||||
'verbose_name_plural': '导航菜单',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='NavigationMenuItem',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('label', models.CharField(max_length=50, verbose_name='文案')),
|
||||
('link_url', models.CharField(blank=True, help_text='留空则使用内部页面链接', max_length=255, verbose_name='外部链接')),
|
||||
('open_in_new_tab', models.BooleanField(default=False, verbose_name='新标签页打开')),
|
||||
('link_page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.page', verbose_name='内部页面')),
|
||||
('menu', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='core.navigationmenu')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['sort_order'],
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Partner',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='名称')),
|
||||
('website_url', models.URLField(blank=True, verbose_name='官网链接')),
|
||||
('order', models.IntegerField(default=0, verbose_name='排序')),
|
||||
('logo', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='Logo')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '合作伙伴',
|
||||
'verbose_name_plural': '合作伙伴',
|
||||
'ordering': ['order', 'id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SiteSettings',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('company_name', models.CharField(blank=True, max_length=100, verbose_name='公司全称')),
|
||||
('contact_phone', models.CharField(blank=True, max_length=30, verbose_name='联系电话')),
|
||||
('contact_email', models.EmailField(blank=True, max_length=254, verbose_name='联系邮箱')),
|
||||
('address', models.CharField(blank=True, max_length=255, verbose_name='公司地址')),
|
||||
('icp_number', models.CharField(blank=True, max_length=50, verbose_name='ICP备案号')),
|
||||
('icp_url', models.URLField(default='https://beian.miit.gov.cn/', verbose_name='备案查询链接')),
|
||||
('wechat_account', models.CharField(blank=True, max_length=100, verbose_name='微信公众号名称')),
|
||||
('weibo_url', models.URLField(blank=True, verbose_name='微博主页')),
|
||||
('site', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, to='wagtailcore.site')),
|
||||
('wechat_qrcode', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='微信公众号二维码')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '站点设置',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TeamMember',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=50, verbose_name='姓名')),
|
||||
('role', models.CharField(blank=True, max_length=100, verbose_name='职位')),
|
||||
('bio', models.TextField(blank=True, verbose_name='简介')),
|
||||
('order', models.IntegerField(default=0, verbose_name='排序')),
|
||||
('photo', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='照片')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '团队成员',
|
||||
'verbose_name_plural': '团队成员',
|
||||
'ordering': ['order', 'id'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Testimonial',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('quote', models.TextField(verbose_name='推荐语')),
|
||||
('author_name', models.CharField(max_length=50, verbose_name='客户姓名')),
|
||||
('author_title', models.CharField(blank=True, max_length=100, verbose_name='客户职位/公司')),
|
||||
('order', models.IntegerField(default=0, verbose_name='排序')),
|
||||
('author_photo', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image', verbose_name='客户头像')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '客户证言',
|
||||
'verbose_name_plural': '客户证言',
|
||||
'ordering': ['order', 'id'],
|
||||
},
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user