Django部署Heroku后评论表单用户下拉列表为空问题咨询
问题根因
核心问题是代码里存在两套完全独立、无关联的User模型,和Heroku部署环节本身无关:
- 你在
main/models.py里自定义了User模型,对应后台「Main」板块下的用户数据;Django自带的django.contrib.auth.models.User是认证系统用的用户模型,对应后台「AUTHENTICATION AND AUTHORIZATION」板块下的用户数据,二者是完全分开的两张数据库表,没有任何自动同步逻辑。 - 现有注册逻辑调用的是Django内置认证系统的用户创建接口,新用户只会写入认证系统的User表,不会自动在你自定义的main.User表生成记录。
- 评论表单的用户下拉列表取的是main.User表的全部数据,这张表本身没有对应注册用户的记录,自然显示为空。
- 本地之前表现"正常"只是因为你曾经手动在main.User表里添加过测试数据,新注册用户不同步到Main板块的问题本地一直存在,只是之前未排查到。
修复方案
推荐使用第一种方案,是Django官方认可的自定义用户模型的标准实现,长期维护不会出现数据不一致问题。
方案1:统一用户模型(推荐)
- 修改
main/models.py中的自定义User模型,继承Django内置的AbstractUser,替换原有独立的User模型定义:from django.db import models from django.contrib.auth.models import AbstractUser from decimal import Decimal import locale import logging class User(AbstractUser): # AbstractUser已经自带username、password、email、first_name、last_name等认证所需的默认字段 # 如果你需要保留自定义的邮箱字段,可以取消下一行的注释,不需要就直接删除 # email_address = models.EmailField('User Email Address') def __str__(self): return self.first_name + ' ' + self.last_name - 打开项目全局的
settings.py,添加配置指定自定义User模型为项目默认认证模型:AUTH_USER_MODEL = 'main.User' - 清理旧的迁移和脏数据(因为之前已经生成过错误的用户模型迁移,必须做这步否则会报字段冲突):
- 本地操作:删除main app下
migrations文件夹里除__init__.py之外的所有文件,删除本地的db.sqlite3数据库文件 - Heroku操作:如果Heroku端没有需要保留的生产数据,执行
heroku run python manage.py flush清空数据库,或者直接重建Heroku Postgres实例
- 本地操作:删除main app下
- 重新生成并执行迁移:
本地终端执行:
代码推送到Heroku后,在Heroku端执行迁移:python manage.py makemigrations python manage.py migrateheroku run python manage.py migrate - 重新创建超级管理员账号:
# 本地 python manage.py createsuperuser # Heroku端 heroku run python manage.py createsuperuser - 修正评论提交视图的逻辑漏洞:当前视图没有绑定评论和提交用户的关系,用户可以通过下拉列表冒用其他人身份提交评论,直接取当前登录用户即可,修改
add_review视图:
对应可以把@login_required def add_review(request, product_id): product = get_object_or_404(Product, pk=product_id) form = ReviewAdd(request.POST or None) if form.is_valid(): new_rating = form.save(commit=False) new_rating.product = product new_rating.user = request.user # 绑定当前登录用户,不需要用户手动选择 new_rating.save() return redirect('home') return render(request, 'main/add_review.html',{'form':form})ReviewAdd表单里的用户选择字段删除,避免越权问题。 - 部署检查:确认推送到Heroku的代码包含所有最新生成的迁移文件,每次部署后必须在Heroku端执行
migrate命令同步表结构。
方案2:保留双模型,注册时同步数据(不推荐)
如果暂时不想重构用户模型,可以修改注册逻辑,在用户完成认证注册后,同步在main.User表创建对应记录:
def register(response): if response.method == "POST": form = RegisterForm(response.POST) if form.is_valid(): new_user = form.save() # 同步创建Main板块下的用户记录 from .models import User as MainUser MainUser.objects.create( first_name=new_user.first_name, last_name=new_user.last_name, email_address=new_user.email ) new_user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password1'],) login(response, new_user) return HttpResponseRedirect("/home") else: form = RegisterForm() return render(response,"register/register.html", {"form":form})
注意这个方案需要手动给所有已经注册的老用户补建main.User表的对应记录,否则老用户依然不会出现在评论下拉列表里,后续用户修改个人信息时也需要做双表同步,维护成本很高。
内容的提问来源于stack exchange,提问作者PhilM
相关产品推荐
相关产品推荐

