Bitpoll 0.11.0 常用 CLI 命令详解

Bitpoll 0.11.0 运维命令与 HTTP 接口实操:manage.py 全命令实测(check/migrate/createsuperuser/shell/dumpdata/generate_encryption_key)、dbbackup 缺失正解 pg_dump、会话+CSRF 建投票与 CSV 导出,含五则排障实录。

Bitpoll自托管DjangoPostgreSQLPython2026/11/01

Bitpoll 0.11.0 常用 CLI 命令详解

Bitpoll 的运维面就是一个标准 Django 项目的 manage.py,外加两个项目自带命令;对外的「API」实为会话 + CSRF 的表单 HTTP 接口与 CSV 导出。本文全部命令与回显均为 2026-11-01 在 0.11.0 实测环境照抄。前置部署见《Bitpoll 0.11.0 Compose 部署实战》,配置面见《Bitpoll 0.11.0 配置参数详解》。

一、命令入口

应用进程内的工作目录是 /opt/bitpoll,管理脚本为 /opt/bitpoll/manage.py。在编排部署形态下统一调用形态:

docker compose exec -T bitpoll python3 /opt/bitpoll/manage.py <子命令>

下文简写为 manage.py <子命令>。-T 关闭伪终端分配,适合脚本化;需要交互(如 createsuperuser 输密码)时去掉 -T。

二、命令总览(实测 help 回显)

manage.py help

实测回显(节选,按 app 分组):

Available subcommands:

[auth]
    changepassword
    createsuperuser

[base]
    importolddudel

[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

[encrypted_model_fields]
    generate_encryption_key

[sessions]
    clearsessions

[staticfiles]
    collectstatic
    findstatic

运维高频项:check、migrate、showmigrations、createsuperuser、changepassword、shell、dumpdata/loaddata、dbshell、generate_encryption_key、clearsessions;迁移专用 importolddudel。

三、逐命令详解

3.1 check —— 部署体检

manage.py check

实测回显:

System check identified no issues (0 silenced).

改完配置、升级后第一件事。它按当前 settings_local 全量跑 Django 系统检查(模型、中间件、模板配置)。

3.2 migrate / showmigrations —— 数据库结构

应用启动脚本每次都会自动执行 migrate,日常无需手工跑;排障或升级后确认状态用:

manage.py migrate
manage.py showmigrations

实测回显:

  No migrations to apply.
  Your models in app(s): 'base', 'django_token_bucket' have changes that are not yet reflected in a migration, and so won't be applied.
  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
 [X] 0015_poll_hide_participants
 [X] 0016_auto_20171114_1536
 [X] 0017_poll_allow_unauthenticated_vote_changes
 [X] 0018_poll_show_score_in_summary
 [X] 0019_alter_choice_id_alter_choicevalue_id_and_more
 [X] 0020_alter_poll_allow_unauthenticated_vote_changes
sessions
 [X] 0001_initial

说明两点:[X] 即已应用,全绿为正常;第二行的 models-changes 警告是 master 分支源码与迁移文件的已知偏差(base 与限流 app 的模型字段有未落迁移的微调),不影响运行,不要顺手执行 makemigrations——那会生成与官方迁移链不一致的新文件,升级时制造冲突。

3.3 createsuperuser —— 管理员初始化

交互形态(标准 TTY 下)按提示依次输入 Username / Email / Password:

manage.py createsuperuser

脚本化形态用 --noinput + 环境变量(实测):

docker compose exec -T -e DJANGO_SUPERUSER_PASSWORD=q1w2e3r4 bitpoll \
  python3 /opt/bitpoll/manage.py createsuperuser --username ops --email ops@quzuo.net --noinput

实测回显:

Superuser created successfully.

坑:非 TTY 下不带 --noinput 直接管道灌密码会被拒(实测回显):

Superuser creation skipped due to not running in a TTY. You can run `manage.py createsuperuser` in your project to create one manually.

示例账号 admin / q1w2e3r4 即由该命令创建(密码务必替换)。

3.4 changepassword —— 改密码

manage.py changepassword admin

交互输入两次新密码,回显 Changing password for user 'admin'. / Password changed successfully for user 'admin'.。忘密兜底也可用 --database 无关的 Django 方式:shell 里 u.set_password(...)(见 3.5)。

3.5 shell —— 数据查询与治理

manage.py shell 进入带 ORM 的 Python 会话,-c 直接执行语句。实测(列投票、删演示账号):

manage.py shell -c "
from bitpoll.poll.models import Poll
from bitpoll.base.models import BitpollUser
print('polls:', list(Poll.objects.values_list('url','title')))
u = BitpollUser.objects.get(username='ops')
u.delete()
print('ops deleted, users now:', list(BitpollUser.objects.values_list('username', flat=True)))
"

实测回显:

polls: [('weekly-meeting', '项目周会时间投票'), ('sprint-review', 'Sprint 回顾表决')]
ops deleted, users now: ['admin']

常用治理操作:

# 删除某投票(软删标记 deleted=True,见 poll/models.py)
Poll.objects.filter(url='sprint-review').update(deleted=True)
# 关闭某投票的匿名
p = Poll.objects.get(url='weekly-meeting'); p.anonymous_allowed = False; p.save()

3.6 dbshell —— 直连数据库(有坑)

manage.py dbshell

实测回显报错:

CommandError: You appear not to have the 'psql' program installed or on your path.

官方应用运行环境不打包 psql 客户端。等价替代——从数据库侧进(实测可用):

docker compose exec -T db psql -U bitpoll -d bitpoll -c "select count(*) from django_migrations;"

回显:

 count 
-------
    64
(1 row)

3.7 dumpdata / loaddata —— JSON 逻辑备份

manage.py dumpdata poll.Poll

实测回显(节选,完整 JSON 含每投票的匿名/登录门槛字段):

[{"model": "poll.poll", "pk": 1, "fields": {"title": "项目周会时间投票", "description": "请选择方便的时间", "url": "weekly-meeting", "type": "date", "created": "2026-11-01T10:36:57.935Z", "user": null, "group": null, "due_date": "2026-11-09T16:00:00Z", "anonymous_allowed": true, "public_listening": true, "require_login": false, "require_invitation": false, "show_results": "complete

备份建议按 app 导出:manage.py dumpdata poll base > poll_backup.json;恢复 manage.py loaddata poll_backup.json(目标库需先清空对应表或用事务包裹)。JSON 层备份适合「迁数据」,整库灾备用 3.9 的 pg_dump。

3.8 generate_encryption_key —— 加密密钥生成

配置详解节 FIELD_ENCRYPTION_KEY 的官方生成命令,实测:

manage.py generate_encryption_key

回显(示例值):

laJl7CZjhuNSZDzF35YG_7DPAmKr_X7Mgo0ZQ7oNdHg=

直接粘贴进 settings.py 的 FIELD_ENCRYPTION_KEY。

3.9 备份命令的正解:pg_dump(dbbackup 不存在)

部分教程会写 manage.py dbbackup——那是第三方包 django-dbbackup 的命令,Bitpoll 官方并未内置。实测回显:

Unknown command: 'dbbackup'
Type 'manage.py help' for usage.

整库备份用数据库侧工具(实测):

docker compose exec -T db pg_dump -U bitpoll bitpoll > backup.sql

产物 64KB 级,头部:

--
-- PostgreSQL database dump
--

恢复:docker compose exec -T db psql -U bitpoll -d bitpoll < backup.sql。把该命令挂 cron 即为最简灾备。

3.10 importolddudel —— 历史数据迁移

项目自带命令([base] 组),用于把前身 opatut/dudel(Flask 版)的数据库导入 Bitpoll:manage.py importolddudel <dudel 数据库连接串>。仅从 dudel 升级的实例用得到,新装实例无需关心。

3.11 低频但有用

  • clearsessions:清理过期会话表行(django_session 膨胀时跑)。
  • sendtestemail --managers:给管理员邮箱发测试邮件,验证第八节配置详解里的 SMTP 链路(console 后端时邮件打到应用进程日志)。
  • diffsettings:打印相对 Django 全局默认的差集,排查「到底哪层配置生效」时最快。
  • compilemessages:官方 locale/ 翻译更新后重编译 .mo。

四、HTTP 接口实操

Bitpoll 无独立 REST 路由(源码 urls.py 全量核对:仅页面路由 + /admin/ + /caldav/),自动化走「会话 + CSRF 表单」与「CSV 导出」两条实测路径。

4.1 登录拿会话

TOKEN=$(curl -s -c cookies.txt "http://127.0.0.1:8136/login/" | grep -oE 'csrfmiddlewaretoken" value="[^"]+' | head -1 | cut -d'"' -f3)
curl -s -b cookies.txt -c cookies.txt -e "http://127.0.0.1:8136/login/" \
  -d "csrfmiddlewaretoken=$TOKEN&username=admin&password=q1w2e3r4&next=/settings/" \
  -o /dev/null -w "login HTTP %{http_code} redirect=%{redirect_url}\n" \
  "http://127.0.0.1:8136/login/"

实测回显:

login HTTP 302 redirect=http://127.0.0.1:8136/settings/

注意登录端点是根路径 /login/,页内出现的 /account/login/ 是注册流程中转,对它 POST 返回 404。

4.2 创建投票(表单流)

登录态下 POST 首页创建表单,成功 302 进选项编辑页。实测回显:

HTTP/1.1 302 Found
Server: nginx/1.23.4
Location: /poll/sprint-review/edit/choices/universal/
Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self'

随后 GET /poll/sprint-review/ 返回 200,标题 <title>Sprint 回顾表决 - Bitpoll</title>。

4.3 CSV 导出结果

任意投票 URL 加 .csv 即导出(poll_export_csv 路由),无需登录(受投票自身访问级别约束)。实测:

curl -s "http://127.0.0.1:8136/poll/weekly-meeting.csv"

回显:

Name,Datetime,2026-11-05 00:00:00+00:00,2026-11-06 00:00:00+00:00,2026-11-07 00:00:00+00:00
Alice,2026-11-01T10:38:50+00:00,yes,no,maybe
Bob,2026-11-01T11:13:07+00:00,yes,yes,maybe

列头为选项(日期),每行一个投票人,值 yes/no/maybe——可直接喂给脚本做「多数时间」统计。

五、日常运维组合

晨检三件套(实测全绿形态):

docker compose ps                                  # 三服务 Up,db 带 healthy
manage.py check                                    # no issues
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8136/   # 200

每周备份:

docker compose exec -T db pg_dump -U bitpoll bitpoll > backup_$(date +%F).sql
manage.py dumpdata poll base > logical_$(date +%F).json

六、排障实录

  1. Unknown command: 'dbbackup':官方未内置 django-dbbackup,备份正解是 pg_dump(3.9)。
  2. dbshell 报 no psql:应用运行环境无数据库客户端,改从数据库侧 psql 进(3.6)。
  3. 管道灌密码建管理员被 skipped:非 TTY 必须 --noinput + DJANGO_SUPERUSER_PASSWORD(3.3)。
  4. migrate 尾随 models-changes 警告:master 源码与迁移文件的已知偏差,不阻塞、勿 makemigrations(3.2)。
  5. 登录 POST 404:端点应为 /login/ 而非页面里出现的 /account/login/(4.1)。

七、关联阅读

Bitpoll 0.11.0 常用 CLI 命令详解 - Quzuo