ImportError: no se puede importar el nombre ‘…’ del módulo parcialmente inicializado ‘…’ (probablemente debido a una importación circular)

6 minutos de lectura

Avatar de usuario de 3WZ
3WZ

Estoy actualizando una aplicación de Django 1.11.25 (Python 2.6) a Django 3.1.3 (Python 3.8.5) y, cuando ejecuto manage.py makemigrationsrecibo este mensaje:

  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)**

Mis modelos son:

autenticación / modelos.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

corporativo / modelos / __init__.py

...
from .section import Section
...

corporativo / modelos / seccion.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, ...)
    ...

¿Qué estoy haciendo mal?

  • Actualice la pregunta para mostrar las importaciones en la parte superior de authentication/models.py.

    – John Gordon

    12 de noviembre de 2020 a las 15:52

  • Ahora que obtuviste la respuesta de lo que hiciste mal, aquí hay algo de ayuda real: Usa from module import * (en algunos casos).

    – usuario136036

    4 de marzo de 2021 a las 21:42

  • Este error puede ocurrir en caso de que el nombre de su archivo sea el mismo que el nombre del paquete que conecta. Simplemente cambie el nombre de su archivo y funcionará.

    – zorro astuto

    18/09/2021 a las 15:33

  • ¿Responde esto a tu pregunta? no se puede importar el nombre ‘mydb’ del módulo ‘conexión’ parcialmente inicializado en Python

    – Marca

    11 de febrero a las 17:35

  • Realmente no entendía cuál era el problema, así que usé el otro modelos.py desde donde importé modelos e hice el modelo allí y funcionó.

    – Usuario anónimo

    17 de agosto a las 5:23

Para futuros lectores, esto también puede suceder si nombra un archivo de python con el mismo nombre que una dependencia que usa su proyecto.

Por ejemplo:

No puedo tener un archivo llamado retrying.py que esté usando el paquete de reintento.

Suponiendo que tuviera el paquete de reintento en mi proyecto, no podría tener un archivo llamado retrying.py con el siguiente contenido:

from retrying import retry
print("HI")

Se produciría un error similar con el mensaje “lo más probable es que se deba a una importación circular”.

El mismo contenido funcionaría bien si cambiara el nombre del archivo a “reintentar_ejemplo1.py”

  • ¡Gracias, esto resolvió mi problema! Tenía un archivo llamado “token.py”, y solo después de cambiarle el nombre a “generate-token.py”, pude ejecutarlo correctamente.

    –Leonardo Gómez

    13 de mayo a las 16:08

  • @LeonardoGomes Es gracioso que digas esto. Nombré mi archivo exactamente como “token.py” y me metí en este problema 🙂

    – dobladillo

    28 de junio a las 2:17

  • ¡Me alegro de haberte podido ayudar!

    – rishikarri

    29 de junio a las 1:14

Avatar de usuario de John Gordon
Juan Gordon

Tienes una importación circular.

authentication/models importaciones corporate/modelsque importa corporate/models/sectioncual imports authentication/models.

No puedes hacer eso.

  • Quiero decir, sí. No puedes hacer eso. Pero algún sentido de cómo abordarlo podría ser útil.

    – thms

    30 de junio de 2021 a las 16:34

  • simplemente cambie el nombre de su archivo. P.ej. no puede tener ray.py e importar ray como un paquete.

    – Jonathan

    13 de septiembre de 2021 a las 12:06

Al importar código de otros archivos, ayuda si deletrea la totalidad subpaquete de donde proviene lo que desea importar. Digamos que tiene la siguiente estructura de archivos:

mypackage/
  subpackage/
    __init__.py
    helper.py
  main/
    work.py

Si:

  • __init__.py importa cosas de helper.py (para que el usuario final acceda cómodamente)
  • y tu estas trabajando adentro work.py
  • y necesitas algo de subpackage/helper.py

Entonces en lugar de hacer:

from ..subpackage import thing_i_need

En su lugar, debe hacer:

from ..subpackage.helper import thing_i_need

Para un código razonable, esto debería ayudarlo a evitar algunos de los problemas de dependencia circular, ya que ahora ya no depende de __init__.py para terminar por completo.

Recibí este error cuando intenté hacer una importación relativa. Tenía dos archivos de modelos:

utils.models:

class BaseModel(models.Model):
    ...

main.models:

from .models import BaseModel
...

El problema se solucionó cuando, en main.modelslo cambié a:

from utils.models import BaseModel

En mi caso el problema fue que definí la función en el archivo x.py y en el archivo x.py importo modelos del archivo modals.py y en el archivo modals.py traté de importar esta función que estaba tratando de establezca el valor predeterminado después de consultar las tablas con esta función

¿Ha sido útil esta solución?