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 makemigrations , recibo 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?
Tienes una importación circular.
authentication/models importa modelos corporate/models , que importa corporate/models/section , que imports authentication/models .
No puedes hacer eso.
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"
Al importar código de otros archivos, ayuda si explicas todo el subpaquete de donde proviene lo que deseas importar. Digamos que tiene la siguiente estructura de archivos:
mypackage/ subpackage/ __init__.py helper.py main/ work.pySi:
__init__.py importa cosas de helper.py (para que el usuario final acceda cómodamente)work.pysubpackage/helper.pyEntonces en lugar de hacer:
from ..subpackage import thing_i_needEn 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 finalizar por completo.
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
Cambiar el nombre de archivo de su archivo de trabajo resuelve el problema en mi caso. Es para la importación circular fbprophet.