ImportError: cannot import name '...' from partially initialized module '...'(很可能是由于循环导入)

问题描述 投票:0回答:12

我正在将应用程序从 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 django importerror python-module circular-dependency
12个回答
222
投票

对于未来的读者,如果您将 python 文件命名为与项目使用的依赖项同名,也会发生这种情况。

例如:

我不能有一个名为 retrying.py 的文件正在使用重试包。

假设我的项目中有重试包,我不能有一个名为 retrying.py 的文件包含以下内容:

from retrying import retry
print("HI")

会出现类似消息“很可能是由于循环导入”的错误。

如果我将文件重命名为“retrying_example1.py”,同样的内容也可以正常工作


41
投票

你有一个循环导入。

authentication/models
进口
corporate/models
,进口
corporate/models/section
,进口
authentication/models
.

你不能那样做。

重新排列你的模块,这样就不需要循环导入了。


8
投票

从其他文件导入代码时,如果您拼出 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
来完全完成。


5
投票

我在尝试进行相对导入时收到此错误。我有两个模型文件:

utils.models

class BaseModel(models.Model):
    ...

main.models

from .models import BaseModel
...

当我在

main.models
中将其更改为:

时,问题已解决
from utils.models import BaseModel

3
投票

在我的例子中,问题是我在 x.py 文件中定义了函数,在 x.py 文件中我从 modals.py 文件导入模型,在 modals.py 文件中我尝试导入这个函数我正在尝试使用此功能查询表后设置默认值


2
投票

我在下面遇到了同样的错误:

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

1
投票

__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

导入之前

1
投票

我遇到了同样的错误。 我正在这样做:(即在蓝图对象创建和模型之前导入我的

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

0
投票

解决循环导入的一种方法是将循环中的文件拆分为多个文件,这样文件就不再相互导入了。在这种情况下,我认为如果将

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):
...

0
投票

循环导入发生在两个或多个模块相互依赖时。 面对这个问题,但不确定问题出在哪里。采用新逻辑并将其添加到自己的单独文件中并且它起作用了,因为模块现在是独立的。


0
投票

我得到这个错误是因为我创建了两个控制器

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
自由调用它而没有任何问题。


-1
投票

我有同样的错误。这是我之前和之后的解决方案。循环导入错误是有道理的。

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
© www.soinside.com 2019 - 2024. All rights reserved.