ImportError cannot import name 'Person' from partially initialized module 'platec.models

Hi team
One question.
I have a Django Project, for which I have been created two apps as follow:

  1. users app: on this app I have created a personalized authentication user model named Person (AUTH_USER_MODEL = ‘users.Person’)
  2. platec app: this app contains the model for users data entry.

On my users.models.py I import models from platec.models.py and it is working correctly, but now I need to import the Person model from my users.models.py into platec app, but when trying to save and run server I get the error:

from platec.models import Factory, Sector, Job_Class, Job_Position, Job_Shift, Area
File “C:\Users\pm25383\OneDrive - Alliance\Documentos\DjangoProject\initProject\platec\models.py”, line 6, in
from .models import Person
ImportError: cannot import name ‘Person’ from partially initialized module ‘platec.models’ (most likely due to a circular import) (C:\Users\pm25383\OneDrive - Alliance\Documentos\DjangoProject\initProject\platec\models.py)

Can you help me to understood why is not possible? most likely i am doing something wrong is so, can you help me to guide me to fix it?

Below you could fine models from both app users and platec and the settings.py file

users.models.py

from django.shortcuts import render
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.contrib.auth.hashers import check_password
from platec.models import Factory, Sector, Job_Class, Job_Position, Job_Shift, Area



class UserManager(BaseUserManager):
    def create_user(self, email, IPN, person_name, password = None):
        if not email:
            raise ValueError("User must have a valid email address")
        
        user = self.model(
            IPN = IPN, 
            email = self.normalize_email(email), 
            person_name = person_name
            )
        
        user.set_password(password)
        user.save()
        return user
    
    def create_superuser(self, email, IPN, person_name, password):
        user = self.create_user(
            email,
            IPN = IPN, 
            person_name = person_name,
            password = password
        )
        user.isAdmin = True
        user.save()
        return user


class Person(AbstractBaseUser):
    IPN =  models.CharField(unique=True, max_length=7, null=False, blank=False)
    person_name = models.CharField(max_length=100, null=False, blank=False)
    supervisor = models.ForeignKey("self", on_delete=models.PROTECT, null=True, blank=True)
    email = models.EmailField(max_length=100, null=False, blank=False, unique=True)
    job_shift = models.ForeignKey(Job_Shift, on_delete=models.PROTECT, null=True, blank=True)
    job_position = models.ForeignKey(Job_Position, on_delete=models.PROTECT, null=True, blank=True)
    job_class = models.ForeignKey(Job_Class, on_delete=models.PROTECT, null=True, blank=True)
    factory = models.ForeignKey(Factory, on_delete=models.PROTECT, null=True, blank=True)
    sector = models.ForeignKey(Sector, on_delete=models.PROTECT, null=True, blank=True)
    area = models.ForeignKey(Area, on_delete=models.PROTECT, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    isActive = models.BooleanField(default=True, null=False, blank=False)
    isAdmin = models.BooleanField(default=True, null=False, blank=False)
    isSupervisor = models.BooleanField(default=False, null=False, blank=False)
    isNewUser = models.BooleanField(default=True, null=False, blank=False)

    objects = UserManager()

    USERNAME_FIELD = 'IPN'
    REQUIRED_FIELDS = ['person_name', 'email']	
    
    def __str__(self) -> str:
        return f"{self.person_name}"
    
    def has_perm(self, perm, obj = None):
        return True
    
    def has_module_perms(self, app_label):
        return True
   
    @property
    def is_staff(self):
        return self.isAdmin
    

This is my models.py from platec app:

from django.db import models
from django.db.models import UniqueConstraint
from django.conf import settings
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from .models import Person

# Create your models here.

class IsActive(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_active=True)
    


class SoftDelete(models.Model):
    is_active = models.BooleanField(default=True, null=False, blank=False)
    
    all_records = models.Manager()
    active_records = IsActive()

    def soft_delete(self):
        self.is_active = False
        self.save()

    def undelete(self):
        self.is_active = True
        self.save()

    class Meta:
        abstract = True



class SoftDeleteManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_active = True)



class Competency(SoftDelete):
    competency_id = models.AutoField(primary_key=True, null=False, blank=False)
    competency_cd = models.CharField(max_length=4, unique=True, null=False, blank=False)
    competency_name = models.CharField(max_length=60, unique=True, null=False, blank=False)
    competency_parent = models.ForeignKey("self", on_delete=models.PROTECT, null=True, blank= True)
    comments = models.CharField(max_length=400, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='c_competency')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='m_competency')

    class CompetencyTypeChoices(models.TextChoices):
        prevista = "GRL", _("Geral")
        confirmada = "ESP", _("Especifica")

    competency_type = models.CharField(max_length=3, choices=CompetencyTypeChoices.choices) 


    def __str__(self) -> str:
        return f"{self.competency_name}"
    

    

class Factory(SoftDelete):
    factory_id = models.AutoField(primary_key=True, null=False, blank=False)
    factory_cd = models.CharField(max_length=3, null=False, blank=False, unique=True)
    factory_name = models.CharField(max_length=100, null=False, blank=False)
    factory_desc = models.CharField(max_length=200, null=True, blank=True)
    comments = models.CharField(max_length=400, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='cr_factory')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='lm_factory')
    
    def __str__(self) -> str:
        return f"{self.factory_name}"
    


class Sector(SoftDelete):
    sector_id = models.AutoField(primary_key=True, null=False, blank=False)
    sector_cd = models.CharField(max_length=3, null=False, blank=False, unique=True)
    sector_name = models.CharField(max_length=100, null=False, blank=False)
    sector_desc = models.CharField(max_length=200, null=True, blank=True)
    comments = models.CharField(max_length=400, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='cr_sector')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='lm_sector')
    
    def __str__(self) -> str:
        return f"{self.sector_name}"
    


class Area(SoftDelete):
    area_id = models.AutoField(primary_key=True, null=False, blank=False)
    area_cd = models.CharField(max_length=4, null=False, blank=False, unique=True)
    area_name = models.CharField(max_length=100, null=False, blank=False)
    area_desc = models.CharField(max_length=200, null=True, blank=True)
    comments = models.CharField(max_length=400, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='cr_sector')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='lm_sector')
    
    def __str__(self) -> str:
        return f"{self.area_name}"




class factory_Sector(SoftDelete):
    fac_set_id = models.AutoField(primary_key=True, null=False, blank=False)
    factory = models.ForeignKey(Factory, on_delete=models.PROTECT)
    sector = models.ForeignKey(Sector, on_delete=models.PROTECT)
    area = models.ForeignKey(Area, on_delete=models.PROTECT)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='c_factory_sector')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='m_factory_sector')
    
    class Meta:
        constraints = [
            UniqueConstraint(fields=['factory', 'sector', 'area'], name='unique_Factory_Sector_Area')
        ]

    def __str__(self) -> str:
        return f"{self.factory} - {self.sector} - {self.area}"
    


class Job_Class(SoftDelete):
    job_class_id = models.AutoField(primary_key=True, null=False, blank=False)
    job_class_cd = models.CharField(max_length=3, null=False, blank=False, unique=True)
    job_class_name = models.CharField(max_length=50, null=False, blank=False)
    comments = models.CharField(max_length=400, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='c_job_class')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='m_job_class')

    def __str__(self) -> str:
        return f"{self.job_class_name}"
    
    

class Job_Position(SoftDelete):
    position_id = models.AutoField(primary_key=True, null=False, blank=False)
    position_name = models.CharField(max_length=50, null=False, blank=False, unique=True)
    position_desc = models.CharField(max_length=200, null=True, blank=True)
    sap_cd = models.CharField(max_length=10, null=True, blank=True)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='c_job_position')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='m_job_position')

    def __str__(self) -> str:
        return f"{self.position_name}"



class Job_Shift(SoftDelete):
    job_shift_id = models.AutoField(primary_key=True, null=False, blank=False)
    job_shift_name = models.CharField(max_length=50, null=False, blank=False)
    start_hour = models.TimeField(null=False, blank=False)
    end_hour = models.TimeField(null=False, blank=False)
    created_dt = models.DateField(auto_now_add=True, null=False, blank=False)
    #created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='c_job_shift')
    last_modify_dt = models.DateField(auto_now=True, null=False, blank=False)
    #last_modify_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='m_job_shift')

    def __str__(self) -> str:
        return f"{self.job_shift_name}"


settings.py

"""
Django settings for initProject project.

Generated by 'django-admin startproject' using Django 4.2.18.

For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""

from pathlib import Path
from django.urls import reverse_lazy

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-a)a6fd%kms@yl!j3r%$ogj504wac2vkprt^45q+7r^hpuxamgx'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'import_export',
    'users',
    'platec',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'initProject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'], # Add the templates directory to the list of directories
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'initProject.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


AUTH_USER_MODEL = 'users.Person'


# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True

LOGIN_URL = 'login/'

LOGIN_REDIRECT_URL = reverse_lazy('users:allPerson')


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = 'static/'

STATICFILES_DIRS = [BASE_DIR / "static"]

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

If there is that tight of a linkage between the two, then it probably should be one app. My first recommendation would be to consolidate these.

In platec.models you have:

from .models import Person

Shouldn’t that be something like:

from users.models import Person

Although that may generate other errors because each models file will be trying to import from the other.

But in platec.models you could remove the import of Person and change lines like this:

created_by = models.ForeignKey(Person, on_delete=models.PROTECT, null=False, blank=False, related_name='c_competency')

To:

created_by = models.ForeignKey("users.Person", on_delete=models.PROTECT, null=False, blank=False, related_name='c_competency')
1 Like

Dear @philgyford

Thanks a lot for the advice.
That is amazing

created_by = models.ForeignKey(“users.Person”, on_delete=models.PROTECT, null=False, blank=False, related_name=‘c_competency’)

there is a lot of information about Django I still need to learn to. But thanks to you all of you guys, and all the documentation I will continue learning new details and getting surrounded of Django.

Thanks, guys, for spend part of your time helping us.