Django应用部署到Apache时出现ForeignKey(None)错误求助
问题:Django部署到Apache出现ForeignKey(None)无效的500错误
问题现象
Django Web应用在Nginx上部署测试正常,但切换到Apache后触发500服务器错误,核心报错:
TypeError: ForeignKey(None) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
Apache错误日志回溯
[Tue Aug 06 19:48:10.945075 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] File "<frozen importlib._bootstrap>", line 688, in _load_unlocked [Tue Aug 06 19:48:10.945077 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] File "<frozen importlib._bootstrap_external>", line 883, in exec_module [Tue Aug 06 19:48:10.945079 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed [Tue Aug 06 19:48:10.945082 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] File "/var/www/mysite/vir/lib/python3.10/site-packages/django/contrib/admin/models.py", line 48, in <module> [Tue Aug 06 19:48:10.945086 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] class LogEntry(models.Model): [Tue Aug 06 19:48:10.945089 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] File "/var/www/mysite/vir/lib/python3.10/site-packages/django/contrib/admin/models.py", line 54, in LogEntry [Tue Aug 06 19:48:10.945090 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] user = models.ForeignKey( [Tue Aug 06 19:48:10.945092 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] File "/var/www/mysite/vir/lib/python3.10/site-packages/django/db/models/fields/related.py", line 959, in __init__ [Tue Aug 06 19:48:10.945094 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] raise TypeError( [Tue Aug 06 19:48:10.945099 2024] [wsgi:error] [pid 344644] [remote 169.255.52.63:23675] TypeError: ForeignKey(None) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
异常来源代码
def __init__( self, to, on_delete, related_name=None, related_query_name=None, limit_choices_to=None, parent_link=False, to_field=None, db_constraint=True, **kwargs, ): try: to._meta.model_name except AttributeError: if not isinstance(to, str): raise TypeError( "%s(%r) is invalid. First parameter to ForeignKey must be " "either a model, a model name, or the string %r" % ( self.__class__.__name__, to, RECURSIVE_RELATIONSHIP_CONSTANT, ) )
已尝试操作
- 修改DB_HOST为服务器地址,触发套接字错误
- 修改PostgreSQL套接字组所属为www-data,500错误依旧
- 本地运行
./manage.py dbshell可正常连接数据库
相关配置文件
Apache虚拟主机配置
<VirtualHost *:80> ServerAdmin admin@adminsite.com DocumentRoot /var/www/mysite ServerName mysite.com Alias /static /var/www/mysite/portal/static <Directory /var/www/mysite/portal/static> Require all granted </Directory> Alias /media /home/admin/media <Directory /home/admin/media> Require all granted </Directory> <Directory /var/www/mysite/portal/portal> <Files wsgi.py> Require all granted </Files> </Directory> WSGIDaemonProcess portal python-path=/var/www/mysite/portal python-home=/var/www/mysite/vir WSGIProcessGroup portal WSGIScriptAlias / /var/www/mysite/portal/portal/wsgi.py ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
wsgi.py内容
import os from django.core.wsgi import get_wsgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'portal.settings') application = get_wsgi_application()
settings.py关键配置
WSGI_APPLICATION = 'portal.wsgi.application' # Database DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': os.getenv('DB_NAME'), 'USER': os.getenv('DB_USER'), 'PASSWORD': os.getenv('DB_PASSWORD'), 'HOST': os.getenv('DB_HOST'), 'PORT': '' } } # User authentication AUTH_USER_MODEL = os.getenv("AUTH_USER_MODEL") AUTHENTICATION_BACKENDS = ['login.backends.EmailBackend',]
环境变量取值:DB_HOST=127.0.0.1,AUTH_USER_MODEL='login.CustomUser'
目录结构
. ├── portal │ ├── login │ ├── manage.py │ ├── portal │ ├── static │ ├── templates │ └── web ├── README.md ├── requirements.txt └── vir ├── bin ├── include ├── lib ├── lib64 -> lib └── pyvenv.cfg
排查思路与解决方案
环境变量未加载导致AUTH_USER_MODEL为None
- 验证:在wsgi.py中添加
print(os.getenv('AUTH_USER_MODEL')),重启Apache后查看错误日志是否输出正确值。若输出None,说明环境变量未被WSGI进程读取。 - 解决:
- 直接在Apache配置的
WSGIDaemonProcess行后添加环境变量:WSGIDaemonProcess portal python-path=/var/www/mysite/portal python-home=/var/www/mysite/vir env=AUTH_USER_MODEL='login.CustomUser' env=DB_NAME='你的数据库名' env=DB_USER='你的数据库用户' env=DB_PASSWORD='你的数据库密码' env=DB_HOST='127.0.0.1' - 或使用
python-dotenv管理环境变量,确保wsgi.py中先加载.env文件:import os from dotenv import load_dotenv load_dotenv() # 加载.env文件 from django.core.wsgi import get_wsgi_application os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'portal.settings') application = get_wsgi_application()
- 直接在Apache配置的
- 验证:在wsgi.py中添加
WSGI进程权限不足
- 检查环境变量文件(如
.env)的权限,确保www-data用户可读取:chmod 644 /var/www/mysite/.env chown :www-data /var/www/mysite/.env
- 检查环境变量文件(如
自定义User模型加载顺序错误
- 确保
loginapp在INSTALLED_APPS中排在django.contrib.admin之前,让Django优先加载自定义User模型。
- 确保
数据库连接验证
- 用www-data用户测试数据库连接:
输入密码后若无法连接,需调整PostgreSQL的pg_hba.conf配置,允许localhost的www-data用户访问。sudo -u www-data psql -h 127.0.0.1 -U 你的数据库用户 你的数据库名
- 用www-data用户测试数据库连接:
内容的提问来源于stack exchange,提问作者t18nao
相关产品推荐
相关产品推荐

