django-wiki 0.13.0 常用 CLI 命令与工具详解

django-wiki 0.13.0 CLI 工具体系全实测:manage.py 命令分组与 help 回显、wiki_notifications_create_defaults/notifymail/thumbnail 扩展命令、dumpdata/loaddata 备份恢复、gunicorn 托管与平滑重启、升级命令顺序与常见坑修复实录

django-wikiPythonDjangoWiki知识库2026/11/01

django-wiki 0.13.0 常用 CLI 命令与工具详解

目标:系统梳理 django-wiki 0.13.0 部署后可用的全部命令行工具——Django manage.py 中与 wiki 运维直接相关的命令(迁移、账号、备份恢复、通知、缩略图、会话、静态文件)、django-wiki 自带的 wiki_notifications_create_defaults、django_nyt 的 notifymail、sorl-thumbnail 的 thumbnail,以及生产托管用的 gunicorn 命令。所有命令与回显均在 Debian 13 + Python 3.12.16 + django-wiki 0.13.0 + Django 6.0.9 环境实测逐行照抄。

一、环境信息

  • 操作系统:Debian 13(trixie)
  • Python:3.12.16(虚拟环境 /srv/wiki/venv)
  • django-wiki:0.13.0(PyPI 包名 wiki);Django:6.0.9;gunicorn:26.2.0
  • 工程目录:/srv/wiki,settings 模块 wikisite.settings,数据库 SQLite(/srv/wiki/db.sqlite3)
  • 服务监听:gunicorn 绑定 0.0.0.0:8000
  • 演示账号:超级用户 root / q1w2e3r4
  • 下文所有 manage.py 命令均在 /srv/wiki 目录下以 ./venv/bin/python manage.py ... 形式执行

💡 说明:本篇为 CLI 专题篇,不重复安装过程。组件尚未部署的,请先按《Debian 13 安装 django-wiki 0.13.0 指南》完成安装与工程集成;配置参数的语义详见《django-wiki 0.13.0 配置参数详解》。

二、工具概览

django-wiki 没有独立的客户端 CLI,一切运维命令通过 Django 的 manage.py 分发。实测 ./venv/bin/python manage.py help 回显(命令按来源应用分组,逐行照抄):

Type 'manage.py help <subcommand>' for help on a specific subcommand.

Available subcommands:

[auth]
    changepassword
    createsuperuser

[contenttypes]
    remove_stale_contenttypes

[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    loaddata
    makemessages
    makemigrations
    migrate
    optimizemigration
    sendtestemail
    shell
    showmigrations
    sqlflush
    sqlmigrate
    sqlsequencereset
    squashmigrations
    startapp
    startproject
    test
    testserver

[django_nyt]
    notifymail

[notifications]
    wiki_notifications_create_defaults

[sessions]
    clearsessions

[staticfiles]
    collectstatic
    findstatic
    runserver

[thumbnail]
    thumbnail

与 django-wiki 运维直接相关的命令与用途:

命令来源用途
migrate / showmigrations / sqlmigratedjango建表、迁移状态核对、SQL 审查
check / check --deploydjango工程自检、生产部署安全检查
diffsettingsdjango核对哪些配置真正生效
createsuperuser / changepasswordauth管理员建号与改密
dumpdata / loaddatadjango文章数据备份与恢复(JSON fixture)
shell / dbshelldjango交互式查询文章模型 / 数据库
wiki_notifications_create_defaultswiki notifications 插件为存量文章所有者/编辑者补建订阅
notifymaildjango_nyt投递通知邮件(守护/定时两种模式)
thumbnailsorl-thumbnail清理图片插件产生的缩略图缓存
clearsessionssessions清理过期会话
collectstaticstaticfiles收集静态文件
gunicornpip 独立命令生产 WSGI 托管

三、前置条件

  1. 工程已完成 migrate,check 无错误:
cd /srv/wiki
./venv/bin/python manage.py check
System check identified no issues (0 silenced).
  1. 已存在超级用户 root(密码 q1w2e3r4);
  2. 通知相关命令要求 INSTALLED_APPS 含 django_nyt.apps.DjangoNytConfig 与 wiki.plugins.notifications.apps.NotificationsConfig;
  3. thumbnail 命令要求 INSTALLED_APPS 含 sorl.thumbnail。

四、各工具详解

4.1 迁移系:migrate / showmigrations / sqlmigrate

showmigrations 核对 wiki 各应用的迁移是否全部落库(可只点名关心的应用,实测回显):

./venv/bin/python manage.py showmigrations wiki wiki_attachments wiki_images wiki_notifications django_nyt
wiki
 [X] 0001_initial
 [X] 0002_urlpath_moved_to
 [X] 0003_mptt_upgrade
wiki_attachments
 [X] 0001_initial
 [X] 0002_auto_20151118_1816
wiki_images
 [X] 0001_initial
 [X] 0002_auto_20151118_1811
wiki_notifications
 [X] 0001_initial
 [X] 0002_auto_20151118_1811
django_nyt
 [X] 0001_initial
 [X] 0002_notification_settings
 [X] 0003_subscription
 [X] 0004_notification_subscription
 [X] 0005__v_0_9_2
 [X] 0006_auto_20141229_1630
 [X] 0007_add_modified_and_default_settings
 [X] 0008_auto_20161023_1641
 [X] 0009_alter_notification_subscription_and_more
 [X] 0010_settings_created_settings_modified_and_more
 [X] 0011_add_interval_to_disable_email_notifications
 [X] 0012_alter_big_auto_field

全部 [X] 即健康;出现 [ ] 说明有迁移未执行,跑一次 migrate 即可。

sqlmigrate 查看迁移将执行的真实 SQL(升级前审查用,实测输出节选):

./venv/bin/python manage.py sqlmigrate wiki 0001
BEGIN;
--
-- Create model Article
--
CREATE TABLE "wiki_article" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "created" datetime NOT NULL, "modified" datetime NOT NULL, "group_read" bool NOT NULL, "group_write" bool NOT NULL, "other_read" bool NOT NULL, "other_write" bool NOT NULL);
--
-- Create model ArticleForObject
--
CREATE TABLE "wiki_articleforobject" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "object_id" integer unsigned NOT NULL CHECK ("object_id" >= 0), "is_mptt" bool NOT NULL, "article_id" integer NOT NULL REFERENCES "wiki_article" ("id") DEFERRABLE INITIALLY DEFERRED, "content_type_id" integer NOT NULL REFERENCES "django_content_type" ("id") DEFERRABLE INITIALLY DEFERRED);

核心表结构一目了然:wiki_article(权限四字段)+ wiki_articleforobject(与 URLPath 的 contenttypes 桥接)+ wiki_articlerevision(正文、标题、user_message 修订说明、ip_address)等。

4.2 账号系:createsuperuser / changepassword

createsuperuser --noinput(脚本化建号,实测回显):

DJANGO_SUPERUSER_PASSWORD=q1w2e3r4 ./venv/bin/python manage.py createsuperuser --username root --email root@example.com --noinput
Superuser created successfully.

--noinput 跳过全部交互并绕过密码强度校验器,适合批量初始化。

changepassword 交互改密,实测两个坑(详见「六、常见问题」6.1):非 TTY 管道输入会因 getpass 失败抛 EOFError;弱密码会被 AUTH_PASSWORD_VALIDATORS 拦截,实测回显:

This password is too common.
Password: Changing password for user 'root'
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/getpass.py", line 69, in unix_getpass
    old = termios.tcgetattr(fd)     # a copy to save
          ^^^^^^^^^^^^^^^^^^^^^
termios.error: (25, 'Inappropriate ioctl for device')

(中间 traceback 帧略)

EOFError

参数速查(manage.py changepassword --help 实测节选):位置参数 [username](缺省为当前用户)、--database {default}。

4.3 备份与恢复:dumpdata / loaddata

django-wiki 的文章树、修订历史、权限字段全在 wiki 应用的表里,用 Django fixture 机制做逻辑备份最可靠。

dumpdata 导出(实测命令与回显):

./venv/bin/python manage.py dumpdata wiki --indent 2 -o wiki_backup.json
ls -l wiki_backup.json
head -12 wiki_backup.json
-rw-r--r-- 1 root root 10721 Nov  1 13:22 wiki_backup.json
[
{
  "model": "wiki.article",
  "pk": 1,
  "fields": {
    "current_revision": 1,
    "created": "2026-11-01T12:13:37.696Z",
    "modified": "2026-11-01T12:13:37.725Z",
    "owner": null,
    "group": null,
    "group_read": true,
    "group_write": true,

核对备份内容构成:

./venv/bin/python -c "import json,collections; d=json.load(open('wiki_backup.json')); c=collections.Counter(x['model'].split('.')[0] for x in d); print('total objects:', len(d)); print(dict(sorted(c.items())))"
total objects: 26
{'wiki': 26}

loaddata 恢复(对同一文件重放,实测回显):

./venv/bin/python manage.py loaddata wiki_backup.json
Installed 26 object(s) from 1 fixture(s)

loaddata 按主键 upsert,重复执行不产生脏数据;恢复到新库时先 flush 相关应用或保证目标库干净。

dumpdata --help 实测关键参数(逐行照抄要点):

  --format FORMAT       Specifies the output serialization format for fixtures.
  --indent INDENT       Specifies the indent level to use when pretty-printing
                        output.
  --database {default}  Nominates a specific database to dump fixtures from.
                        Defaults to the "default" database.
  -e EXCLUDE, --exclude EXCLUDE
                        An app_label or app_label.ModelName to exclude (use
                        multiple --exclude to exclude multiple apps/models).
  --natural-foreign     Use natural foreign keys if they are available.
  --natural-primary     Use natural primary keys if they are available.
  -a, --all             Use Django's base manager to dump all models stored in
                        the database, including those that would otherwise be
                        filtered or modified by a custom manager.
  --pks PRIMARY_KEYS    Only dump objects with given primary keys. Accepts a
                        comma-separated list of keys. This option only works
                        when you specify one model.
  -o OUTPUT, --output OUTPUT
                        Specifies file to which the output is written.

⚠️ 注意:备份 wiki 应用时建议同时备份 auth(用户表)与附件/图片目录(/srv/wiki/media),否则恢复后文章里的修订作者与上传文件会缺失。

4.4 交互查询:shell / dbshell

shell -c 单行查询文章路径树(实测回显):

./venv/bin/python manage.py shell -c 'from wiki.models import URLPath; print([p.path for p in URLPath.objects.all()])'
32 objects imported automatically (use -v 2 for details).

['', 'getting-started/', 'xss-test/', 'xss-demo/']

URLPath.path 即 URL 中的 slug 路径,空串是根文章。排查「文章 404 / slug 冲突」时先列这张表。

dbshell 直接进入数据库命令行(SQLite 下即 sqlite3 /srv/wiki/db.sqlite3),--help 实测只有 --database {default} 一个专属参数,其余为 Django 通用参数。

4.5 通知系命令:wiki_notifications_create_defaults 与 notifymail

wiki_notifications_create_defaults(notifications 插件提供):遍历全部文章,为所有者与修订编辑者批量补建「文章编辑」订阅。--help 实测:

usage: manage.py wiki_notifications_create_defaults [-h] [--version]
                                                    [-v {0,1,2,3}]
                                                    [--settings SETTINGS]
                                                    [--pythonpath PYTHONPATH]
                                                    [--traceback] [--no-color]
                                                    [--force-color]
                                                    [--skip-checks]

Import and parse messages directly from a CSV file.

(help 文案 "Import and parse messages directly from a CSV file." 是上游源码遗留错误描述,实际功能是补建订阅,无 CSV 参数。)

直接执行在「编辑者从未初始化通知设置」时会崩,实测完整报错(traceback 关键帧逐行照抄):

  File "/srv/wiki/venv/lib/python3.12/site-packages/wiki/plugins/notifications/management/commands/wiki_notifications_create_defaults.py", line 26, in subscribe_to_article
    settings_map[user], __ = Settings.objects.get_or_create(
  File "/srv/wiki/venv/lib/python3.12/site-packages/django/db/models/query.py", line 669, in create
    obj.save(force_insert=True, using=self.db)
  File "/srv/wiki/venv/lib/python3.12/site-packages/django_nyt/models.py", line 238, in save
    raise ValueError("A user must have a default settings object")
ValueError: A user must have a default settings object

根因:命令内 Settings.objects.get_or_create(user=user) 不带 is_default=True,新建的非默认行在「该用户没有任何默认设置行」时被 django_nyt 的 save() 校验拒绝。凡是绕过 wiki 注册页建号(createsuperuser、admin 后台)且编辑过文章的用户都会触发。

修复:先给涉及用户补默认设置行再重跑。脚本 fix_nyt.py:

from django.contrib.auth import get_user_model
from django_nyt.models import Settings
from wiki.models import Article

U = get_user_model()
involved = set()
for a in Article.objects.all():
    if a.owner:
        involved.add(a.owner)
    for r in a.articlerevision_set.exclude(user=None).values("user"):
        involved.add(U.objects.get(id=r["user"]))
print("involved users:", sorted(u.username for u in involved))
missing = [u for u in involved if not Settings.objects.filter(user=u).exists()]
print("users WITHOUT any Settings row:", [u.username for u in missing])
for u in missing:
    Settings.objects.create(user=u, is_default=True)
print("after fix:", list(Settings.objects.values("user__username", "is_default")))

实测执行与重跑(逐行照抄):

./venv/bin/python manage.py shell < fix_nyt.py
./venv/bin/python manage.py wiki_notifications_create_defaults
32 objects imported automatically (use -v 2 for details).

involved users: ['admin', 'editor1']
users WITHOUT any Settings row: ['editor1']
after fix: [{'user__username': 'admin', 'is_default': True}, {'user__username': 'editor2', 'is_default': True}, {'user__username': 'editor1', 'is_default': True}]
Created 8 subscriptions on  4 articles

notifymail(django_nyt 提供):把未发送的订阅通知按各订阅频率投递为邮件。它是独立投递进程,Web 请求不会发信,需常驻(--daemon)或定时(--cron)执行。--help 实测专属参数(逐行照抄):

usage: manage.py notifymail [-h] [--daemon] [--cron] [--pid-file PID]
                            [--domain DOMAIN] [--http-only] [--log-file LOG]
                            [--no-sys-exit]
                            [--daemon-sleep-interval SLEEP_TIME] [--now NOW]
                            [--retries RETRIES]
                            [--retries-cooldown RETRIES_COOLDOWN] [--version]
                            [-v {0,1,2,3}] [--settings SETTINGS]
                            [--pythonpath PYTHONPATH] [--traceback]
                            [--no-color] [--force-color] [--skip-checks]

Sends notification emails to subscribed users taking into account the
subscription interval
  --daemon, -d          Go to daemon mode and exit
  --cron, -c            Do not loop, just send out emails once and exit
  --pid-file PID        Where to write PID before exiting
  --domain DOMAIN       Base domain to use for URLs (excluding HTTP protocol).
  --http-only           Use http:// in URLs instead of https://.
  --log-file LOG        Where daemon should write its log
  --no-sys-exit         Skip sys-exit after forking daemon (mainly for testing purposes)
  --daemon-sleep-interval SLEEP_TIME
                        Minimum sleep between each polling of the database.
  --now NOW             Simulate when to start sending from (mainly for testing purposes)
  --retries RETRIES     How many time to retry if encountering errors when sending the emails
  --retries-cooldown RETRIES_COOLDOWN
                        Time in seconds to wait before trying again to send the emails

直接前台运行(不带 --cron,进入 send-loop 循环)实测回显——未配置 EMAIL_HOST 时 Django 默认连 localhost:25,被拒:

2026-11-01 12:18:15: INFO - Starting django_nyt e-mail dispatcher
Entering send-loop, CTRL+C to exit
2026-11-01 12:18:15: INFO - Starting send loop at 2026-11-01 12:18:15.975447+00:00

(中间为 smtplib 连接栈的 traceback 帧,略)

ConnectionRefusedError: [Errno 111] Connection refused

--cron 单次投递模式同样因 SMTP 不可达失败(末尾回显一致:ConnectionRefusedError: [Errno 111] Connection refused)。把邮件后端临时切为内存队列(EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend')后 --cron 实测正常启动并完成一轮投递:

2026-11-01 12:19:01: INFO - Starting django_nyt e-mail dispatcher

生产用法二选一:

# 方式一:cron 定时(每分钟)
* * * * * cd /srv/wiki && ./venv/bin/python manage.py notifymail --cron >> /var/log/notifymail.log 2>&1

# 方式二:守护模式(自行写 systemd 单元常驻)
./venv/bin/python manage.py notifymail --daemon --pid-file /run/notifymail.pid --log-file /var/log/notifymail.log

4.6 缩略图清理:thumbnail(sorl-thumbnail)

图片插件上传后按 WIKI_IMAGES_THUMBNAIL_SIZES 各档位生成缩略图并缓存在 key-value 表中,thumbnail 命令负责清理。--help 实测(逐行照抄):

usage: manage.py thumbnail [-h] [--version] [-v {0,1,2,3}]
                           [--settings SETTINGS] [--pythonpath PYTHONPATH]
                           [--traceback] [--no-color] [--force-color]
                           [--skip-checks]
                           {cleanup,clear,clear_delete_referenced,clear_delete_all}

Handles thumbnails and key-value store

positional arguments:
  {cleanup,clear,clear_delete_referenced,clear_delete_all}

Documentation: https://sorl-thumbnail.readthedocs.io/en/latest/management.html

四个子动作:cleanup(清孤儿缓存项)、clear(清 key-value 记录)、clear_delete_referenced(连同被引用文件一起删)、clear_delete_all(全删)。定期维护用 cleanup 即可(实测回显):

./venv/bin/python manage.py thumbnail cleanup
Cleanup thumbnails ... [Done]

4.7 会话与静态文件:clearsessions / collectstatic

./venv/bin/python manage.py clearsessions

实测退出码 0(无输出即正常),清掉 django_session 表中的过期行;建议 cron 每日一次。

./venv/bin/python manage.py collectstatic --noinput

实测回显:

0 static files copied to '/srv/wiki/static', 380 unmodified.

升级 django-wiki 或改 STATICFILES_DIRS 后重跑,把新静态资源同步到 STATIC_ROOT 供反代直出。

4.8 配置核对:diffsettings 与 check --deploy

./venv/bin/python manage.py diffsettings | grep WIKI_

实测回显(### 标记项目显式覆写的项):

WIKI_ACCOUNT_HANDLING = True  ###
WIKI_ACCOUNT_SIGNUP_ALLOWED = True  ###

生产上线前安全检查:

./venv/bin/python manage.py check --deploy

实测回显(当前测试环境 DEBUG=True、未配 HTTPS,6 条警告):

WARNINGS:
?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served only over SSL, you may want to consider setting a value and enabling HTTP Strict Transport Security. Be sure to read the documentation first; enabling HSTS carelessly can cause serious, irreversible problems.
?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over both SSL and non-SSL connections, you may want to either set this setting True or configure a load balancer or reverse-proxy server to redirect all connections to HTTPS.
?: (security.W009) Your SECRET_KEY has less than 50 characters, less than 5 unique characters, or it's prefixed with 'django-insecure-' indicating that it was generated automatically by Django. Please generate a long and random value, otherwise many of Django's security-critical features will be vulnerable to attack.
?: (security.W012) SESSION_COOKIE_SECURE is not set to True. Using a secure-only session cookie makes it more difficult for network traffic sniffers to hijack user sessions.
?: (security.W016) You have 'django.middleware.csrf.CsrfViewMiddleware' in your MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. Using a secure-only CSRF cookie makes it more difficult for network traffic sniffers to steal the CSRF token.
?: (security.W018) You should not have DEBUG set to True in deployment.

System check identified 6 issues (0 silenced).

逐项对应处理见《django-wiki 0.13.0 配置参数详解》「生产配置模板」一节。

4.9 服务托管:gunicorn

生产启动命令(工程目录 /srv/wiki):

cd /srv/wiki
./venv/bin/gunicorn wikisite.wsgi:application -b 0.0.0.0:8000 -w 2 \
  --access-logfile /var/log/wiki_access.log --error-logfile /var/log/wiki_error.log \
  --pid /run/wiki.pid --daemon

实测 /var/log/wiki_error.log 启动段(逐行照抄):

[2026-11-01 12:46:47 +0000] [1528] [INFO] Starting gunicorn 26.2.0
[2026-11-01 12:46:47 +0000] [1528] [INFO] Listening at: http://0.0.0.0:8000 (1528)
[2026-11-01 12:46:47 +0000] [1528] [INFO] Using worker: sync
[2026-11-01 12:46:47 +0000] [1529] [INFO] Booting worker with pid: 1529
[2026-11-01 12:46:47 +0000] [1530] [INFO] Booting worker with pid: 1530
[2026-11-01 12:46:47 +0000] [1528] [INFO] Control socket listening at /root/.gunicorn/gunicorn.ctl

改配置后的平滑重启(实测:向主进程发 SIGHUP,旧 worker 退出、新 worker 接管,服务不中断):

kill -HUP $(cat /run/wiki.pid)
tail -6 /var/log/wiki_error.log

实测日志回显(主进程 pid 2009,worker 2010/2011 换为 2141/2143):

[2026-11-01 13:24:15 +0000] [2141] [INFO] Booting worker with pid: 2141
[2026-11-01 13:24:15 +0000] [2009] [INFO] Control socket listening at /root/.gunicorn/gunicorn.ctl
[2026-11-01 13:24:15 +0000] [2143] [INFO] Booting worker with pid: 2143
[2026-11-01 13:24:15 +0000] [2009] [INFO] Control socket listening at /root/.gunicorn/gunicorn.ctl
[2026-11-01 13:24:15 +0000] [2011] [INFO] Worker exiting (pid: 2011)
[2026-11-01 13:24:15 +0000] [2010] [INFO] Worker exiting (pid: 2010)

存活验证:

curl -s -o /dev/null -w 'GET /: %{http_code}\n' http://127.0.0.1:8000/
curl -s http://127.0.0.1:8000/ | grep -o '<title>[^<]*</title>' | head -1
GET /: 200
<title>Home - django-\/\/  i K |</title>

(<title> 里的怪串是 django-wiki 默认首页标题中内嵌 logo 字符画的一部分,属正常现象。)

五、注意事项

  1. notifymail 必须独立调度:邮件不在 Web 进程内发送。忘了跑它,用户订阅了也收不到任何邮件——这是「通知不生效」的第一排查点。
  2. 备份三件套:dumpdata wiki 只覆盖文章数据;完整备份 = fixture + auth/auth_permission 导出 + /srv/wiki/media 目录(附件与图片)+ db.sqlite3 冷备。
  3. makemigrations 不要随手跑:见「六、常见问题」6.2,0.13.0 在 Django 6.x 下存在迁移噪音。
  4. 所有写命令(migrate/loaddata/flush)执行前先 dumpdata:flush 会清空数据库,不可逆。
  5. 命令通用参数:每个子命令都支持 -v {0,1,2,3}、--settings SETTINGS、--pythonpath PYTHONPATH、--skip-checks(实测 --help 均含),多环境共用工程时用 --settings 指定不同 settings 模块最干净。

六、常见问题

6.1 changepassword 脚本化失败:EOFError / termios.error

现象:echo q1w2e3r4 | manage.py changepassword root 报:

Warning: Password input may be echoed.
This password is too common.
termios.error: (25, 'Inappropriate ioctl for device')
EOFError

定位:两层叠加——① changepassword 用 getpass 要求 TTY,管道输入触发回退读取并最终 EOFError;② 即便 TTY 输入,q1w2e3r4 也会被 CommonPasswordValidator 拒绝(This password is too common.)。

解决:改强密码走交互 TTY;批量改密改用 Django API(set_password 不经过校验器):

./venv/bin/python manage.py shell -c '
from django.contrib.auth import get_user_model
u = get_user_model().objects.get(username="root")
u.set_password("Q1w2e3r4!xZ")
u.save()
print("password updated for", u.username)
'

实测回显:

32 objects imported automatically (use -v 2 for details).

password updated for root

6.2 makemigrations --check 总是 exit=1、提示生成 alter 迁移

现象(实测回显):

Migrations for 'wiki':
  venv/lib/python3.12/site-packages/wiki/migrations/0004_alter_article_id_alter_articleforobject_id_and_more.py
    ~ Alter field id on article
    ~ Alter field id on articleforobject
    ~ Alter field id on articleplugin
    ~ Alter field id on articlerevision
    ~ Alter field id on revisionpluginrevision
    ~ Alter field id on urlpath
Migrations for 'wiki_attachments':
  venv/lib/python3.12/site-packages/wiki/plugins/attachments/migrations/0003_alter_attachmentrevision_id.py
    ~ Alter field id on attachmentrevision
exit=1

定位:django-wiki 0.13.0 发布时模型主键与 Django 6.x 项目默认 DEFAULT_AUTO_FIELD = BigAutoField 存在差异,makemigrations 检测到「可把 id 改为 BigAuto」的待生成迁移。这是上游包内迁移状态问题,不是你的库坏了——showmigrations 里 wiki 各应用全部 [X]、check 无 issues 即无需处理。

解决:不要在 CI 里用 makemigrations --check 卡 django-wiki 工程的门禁;确要消除噪音,可把上述 alter 迁移生成在工程内应用并执行(会改表类型,SQLite 下 Django 会建新表迁移数据,务必先备份)。

6.3 notifymail 报 Connection refused

见 4.5 节实测:默认 EMAIL_HOST=localhost:25 不可达。配置真实 EMAIL_HOST/EMAIL_PORT 后重跑;无 SMTP 服务器联调时临时用 locmem 后端验证投递逻辑。

6.4 执行 wiki_notifications_create_defaults 报 ValueError: A user must have a default settings object

完整根因分析与修复脚本见 4.5 节(实测修复后输出 Created 8 subscriptions on 4 articles)。要点:命令不会为「从未初始化通知设置」的用户自动建默认 Settings,先跑 fix_nyt.py 补齐即可。

6.5 升级 django-wiki 版本后的命令顺序

固定三步(每步实测均有回显可核对):

./venv/bin/pip index versions wiki         # 先查当前可用版本(实测最新稳定版为 0.13.0)
./venv/bin/pip install -U wiki             # 不带版本号即升级到 PyPI 最新稳定版
./venv/bin/python manage.py migrate        # 新迁移落库
./venv/bin/python manage.py collectstatic --noinput
./venv/bin/python manage.py check          # 确认 0 issues
kill -HUP $(cat /run/wiki.pid)             # 平滑重启 gunicorn

七、参考链接

django-wiki 0.13.0 常用 CLI 命令与工具详解 - Quzuo