我正在将应用程序从 Django 1.11.25 (Python 2.6) 升级到 Django 3.1.3 (Python 3.8.5),当我运行
manage.py makemigrations
时,我收到此消息:
File "/home/eduardo/projdevs/upgrade-intra/corporate/models/section.py", line 9, in <module>
from authentication.models import get_sentinel**
ImportError: cannot import name 'get_sentinel' from partially initialized module 'authentication.models' (most likely due to a circular import) (/home/eduardo/projdevs/upgrade-intra/authentication/models.py)**
我的模特是:
身份验证/models.py
from django.conf import settings
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models
from django.db.models.signals import post_save
from django.utils import timezone
from corporate.constants import GROUP_SUPPORT
from corporate.models import Phone, Room, Section
from library.exceptions import ErrorMessage
from library.model import update_through_dict
from .constants import INTERNAL_USER, EXTERNAL_USER, SENTINEL_USERNAME, SPECIAL_USER, USER_TYPES_DICT
class UserProfile(models.Model):
user = models.OneToOneField(
'User',
on_delete=models.CASCADE,
unique=True,
db_index=True
)
...
phone = models.ForeignKey('corporate.Phone', on_delete=models.SET_NULL, ...)
room = models.ForeignKey('corporate.Room', on_delete=models.SET_NULL, ...)
section = models.ForeignKey('corporate.Section', on_delete=models.SET_NULL, ...)
objects = models.Manager()
...
class CustomUserManager(UserManager):
def __init__(self, type=None):
super(CustomUserManager, self).__init__()
self.type = type
def get_queryset(self):
qs = super(CustomUserManager, self).get_queryset()
if self.type:
qs = qs.filter(type=self.type).order_by('first_name', 'last_name')
return qs
def get_this_types(self, types):
qs = super(CustomUserManager, self).get_queryset()
qs = qs.filter(type__in=types).order_by('first_name', 'last_name')
return qs
def get_all_excluding(self, types):
qs = super(CustomUserManager, self).get_queryset()
qs = qs.filter(~models.Q(type__in=types)).order_by('first_name', 'last_name')
return qs
class User(AbstractUser):
type = models.PositiveIntegerField('...', default=SPECIAL_USER)
username = models.CharField('...', max_length=256, unique=True)
first_name = models.CharField('...', max_length=40, blank=True)
last_name = models.CharField('...', max_length=80, blank=True)
date_joined = models.DateTimeField('...', default=timezone.now)
previous_login = models.DateTimeField('...', default=timezone.now)
objects = CustomUserManager()
...
def get_profile(self):
if self.type == INTERNAL_USER:
...
return None
def get_or_create_profile(self):
profile = self.get_profile()
if not profile and self.type == INTERNAL_USER:
...
return profile
def update(self, changes):
...
class ExternalUserProxy(User):
objects = CustomUserManager(type=EXTERNAL_USER)
class Meta:
proxy = True
verbose_name = '...'
verbose_name_plural = '...'
class InternalUserProxy(User):
objects = CustomUserManager(type=INTERNAL_USER)
class Meta:
proxy = True
verbose_name = '...'
verbose_name_plural = '...'
def create_profile(sender, instance, created, **kwargs):
if created and instance.type == INTERNAL_USER:
try:
profile = UserProfile()
profile.user = instance
profile.save()
except:
pass
post_save.connect(create_profile, sender=User)
def get_sentinel():
try:
sentinel = User.objects.get(username__exact=SENTINEL_USERNAME)
except User.DoesNotExist:
settings.LOGGER.error("...")
from django.contrib.auth.models import Group
sentinel = User()
sentinel.username = SENTINEL_USERNAME
sentinel.first_name = "..."
sentinel.last_name = "..."
sentinel.set_unusable_password()
sentinel.save()
technical = Group.objects.get(name=GROUP_SUPPORT)
sentinel = User.objects.get(username__exact=SENTINEL_USERNAME)
sentinel.groups.add(technical)
sentinel.save()
return sentinel
企业/模型/
__init__.py
...
from .section import Section
...
企业/模型/部分.py
from django.conf import settings
from authentication.models import get_sentinel
from .room import Room
class Section(models.Model):
...
boss = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel), ...)
surrogate = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel), ...)
room = models.ForeignKey(Room, on_delete=models.SET_NULL, ...)
is_subordinate_to = models.ForeignKey('self', on_delete=models.SET_NULL, ...)
...
我做错了什么?
对于未来的读者,如果您将 python 文件命名为与项目使用的依赖项同名,也会发生这种情况。
例如:
我不能有一个名为 retrying.py 的文件正在使用重试包。
假设我的项目中有重试包,我不能有一个名为 retrying.py 的文件包含以下内容:
from retrying import retry
print("HI")
会出现类似消息“很可能是由于循环导入”的错误。
如果我将文件重命名为“retrying_example1.py”,同样的内容也可以正常工作
你有一个循环导入。
authentication/models
进口corporate/models
,进口corporate/models/section
,进口authentication/models
.
你不能那样做。
重新排列你的模块,这样就不需要循环导入了。
从其他文件导入代码时,如果您拼出 the entire subpackage which you would import thing from which is helpful。假设您具有以下文件结构:
mypackage/
subpackage/
__init__.py
helper.py
main/
work.py
如果:
__init__.py
从helper.py
导入东西(为了最终用户方便访问)work.py
subpackage/helper.py
然后而不是做:
from ..subpackage import thing_i_need
你应该这样做:
from ..subpackage.helper import thing_i_need
对于合理的代码,这应该可以帮助您避免一些循环依赖问题,因为现在您不再依赖
__init__.py
来完全完成。
我在尝试进行相对导入时收到此错误。我有两个模型文件:
utils.models
:
class BaseModel(models.Model):
...
main.models
:
from .models import BaseModel
...
当我在
main.models
中将其更改为:时,问题已解决
from utils.models import BaseModel
在我的例子中,问题是我在 x.py 文件中定义了函数,在 x.py 文件中我从 modals.py 文件导入模型,在 modals.py 文件中我尝试导入这个函数我正在尝试使用此功能查询表后设置默认值
我在下面遇到了同样的错误:
AttributeError: partially initialized module 'math' has no attribute 'pi'(很可能是由于循环导入)
因为我创建了
math.py
,在其中导入了python的math
模块并在其中使用math.pi
如下图:
# "math.py"
import math
print(math.pi)
所以,我把
math.py
改成了my_math.py
:
# "my_math.py"
import math
print(math.pi)
然后,错误解决了:
3.141592653589793
__init__.py
中的导入顺序很重要:
models/init.py
from .a import A
from .b import B
a.py
from models.b import B
...
这会给
ImportError: cannot import name 'B' from partially initialized module 'models' (most likely due to a circular import) (/models/__init__.py)
要解决,
B
的导入应该在A
的
__init__.py
导入之前
我遇到了同样的错误。 我正在这样做:(即在蓝图对象创建和模型之前导入我的
models
使用db
文件中定义的app.py
对象。并且这个main_blueprint正在app.py中注册。)
from ..models.user_model import User as user_model
main = Blueprint('main', __name__)
我通过在创建蓝图对象后导入我的模型来修复它。
main = Blueprint('main', __name__)
# always import models after blueprint object creation.
from ..models.user_model import User as user_model
解决循环导入的一种方法是将循环中的文件拆分为多个文件,这样文件就不再相互导入了。在这种情况下,我认为如果将
get_sentinel
移动到一个单独的文件中,它就会得到解决。
身份验证/models_utils.py
def get_sentinel():
...
企业/模型/部分.py
from django.conf import settings
from authentication.models_utils import get_sentinel
from .room import Room
class Section(models.Model):
...
循环导入发生在两个或多个模块相互依赖时。 面对这个问题,但不确定问题出在哪里。采用新逻辑并将其添加到自己的单独文件中并且它起作用了,因为模块现在是独立的。
我得到这个错误是因为我创建了两个控制器
clients.py
和 users.py
从另一个导入,导致 循环导入
from app.controllers.users import get_user_manager, UserManager
ImportError: cannot import name 'get_user_manager' from partially initialized module 'app.controllers.users' (most likely due to a circular import)
这里是澄清的确切场景:
控制器
client.py
从get_user_manager
导入UserManager
,users.py
以在其功能中使用registerClient
在不使用上述导入的
sendForgetPasswordMailClient
中实现client.py
在
users.py
我从已经从sendForgetPasswordMailClient
导入的clients.py
调用users.py
,导致循环导入
客户端.py
...
from app.controllers.users import get_user_manager, UserManager
async def registerClient(
client_password: ClientPasswordCreate,
client: UserCreate,
user_db: UserManager = Depends(get_user_manager),
db: Session = Depends(get_async_session)
):
...
async def sendForgetPasswordMailClient(client_mail, client_name, link):
...
用户.py
...
from app.controllers.clients import sendForgetPasswordMailClient
class UserManager(BaseUserManager[UserCreate, UserDB]):
...
async def on_after_forgot_password(
self, user: UserDB, token: str, request: Optional[Request] = None
):
link = f'{APP_LINK}?token={token}'
sendForgetPasswordMailClient(user.mail, user.firstName, link)
async def get_user_manager(user_db: SQLAlchemyUserDatabase = Depends(get_user_db)):
yield UserManager(user_db)
解决方案只是将不包含任何导入的
sendForgetPasswordMailClient
从users.py
移动到另一个文件,这样我就可以从users.py
自由调用它而没有任何问题。
我有同样的错误。这是我之前和之后的解决方案。循环导入错误是有道理的。
from resources.file import blp as Home
app = Flask(__name__)
csrf = CSRFProtect(app)
解决方案:
app = Flask(__name__)
csrf = CSRFProtect(app)
from resources.file import blp as Home