在Django的apps.py中使用post_save信号触发AppRegistryNotReady错误咨询
解决Django中post_save信号触发AppRegistryNotReady错误的问题
问题描述
使用Django框架,自定义了User模型,信号逻辑放在独立的signals.py文件中。在apps.py的ready方法中引入信号后,post_migrate信号能正常工作,但连接post_save信号时触发了AppRegistryNotReady错误(提示Apps aren't loaded yet.)。
相关代码
signals.py
import secrets from django.core.mail import send_mail def create_first_account(sender, **kwargs): if sender.name == 'accounts': user = User.objects.get_user_by_username("meidan") if user: return None password = secrets.token_hex(4) user = User.objects.create( username="meidan", email="meidanpk@gmail.com", password=password ) user.is_active= True User.objects.save_me(user) subject = 'Meidan Account' message = password from_email = settings.EMAIL_HOST_USER recipient_list = ['ahmedyasin1947@gmail.com'] send_mail(subject, message, from_email, recipient_list, fail_silently=False) def create_first_account(sender, created, **kwargs): if sender.name == 'accounts': print(created)
apps.py
from django.apps import AppConfig from django.db.models.signals import post_migrate, post_save from django.contrib.auth import get_user_model User = get_user_model() class AccountsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'accounts' def ready(self): from accounts.signals import generate_banks, create_first_account, create_first_account post_migrate.connect(generate_banks, sender=self) post_migrate.connect(create_first_account, sender=self) post_save.connect(create_first_account, sender=User)
报错信息
File "/home/aa/playapp-backend/envMy/lib/python3.10/site-packages/django/apps/registry.py", line 201, in get_model self.check_apps_ready() File "/home/aa/playapp-backend/envMy/lib/python3.10/site-packages/django/apps/registry.py", line 136, in check_apps_ready raise AppRegistryNotReady("Apps aren't loaded yet.") django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
问题原因及解决办法
核心问题
报错根源是在apps.py的模块级别提前调用了get_user_model()。Django启动时会先加载所有AppConfig类,此时应用还未完全初始化,提前获取User模型会触发AppRegistryNotReady错误。post_migrate信号能正常工作是因为它的sender是当前AppConfig(self),不需要提前获取User模型;而post_save信号需要传入User模型作为sender,模块顶部提前获取User的操作打乱了初始化顺序。
修复步骤
- 将
get_user_model()移到ready方法内部:避免在模块加载阶段调用模型相关方法,确保应用初始化完成后再获取User模型。 - 修复
signals.py中的缺陷:补充缺失的User和settings导入,重命名同名函数避免逻辑覆盖。
修正后的代码
修正后的apps.py
from django.apps import AppConfig from django.db.models.signals import post_migrate, post_save class AccountsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'accounts' def ready(self): from django.contrib.auth import get_user_model from accounts.signals import generate_banks, create_first_account_on_migrate, create_first_account_on_save User = get_user_model() post_migrate.connect(generate_banks, sender=self) post_migrate.connect(create_first_account_on_migrate, sender=self) post_save.connect(create_first_account_on_save, sender=User)
修正后的signals.py
import secrets from django.conf import settings from django.core.mail import send_mail from django.contrib.auth import get_user_model User = get_user_model() def create_first_account_on_migrate(sender, **kwargs): if sender.name == 'accounts': try: user = User.objects.get_user_by_username("meidan") if user: return except User.DoesNotExist: password = secrets.token_hex(4) user = User.objects.create( username="meidan", email="meidanpk@gmail.com", password=password ) user.is_active = True User.objects.save_me(user) subject = 'Meidan Account' message = password from_email = settings.EMAIL_HOST_USER recipient_list = ['ahmedyasin1947@gmail.com'] send_mail(subject, message, from_email, recipient_list, fail_silently=False) def create_first_account_on_save(sender, created, **kwargs): if sender.name == 'accounts': print(created)
额外说明
- Django中所有需要获取模型的操作,都应放在
ready方法内部或确保在应用完全加载后执行。 - 信号函数中查询User时,建议用
try...except User.DoesNotExist捕获异常,避免查询不到用户时抛出错误。 - 禁止定义同名函数,否则会覆盖之前的函数定义,导致逻辑丢失。
内容的提问来源于stack exchange,提问作者Ahmed Yasin
相关产品推荐
相关产品推荐

