Django ImportError looks like a loop - python

In my django project I have the following:
apps1/models.py: Post (model)
apps2/models.py: Blogs (model)
apps2/functions.py: get_blogs (method)
The apps1/models.py file imports the Blogs model from apps2/models.py.
The apps2/models.py file imports the get_blogs method from apps2/functions.py.
The apps2/functions.py file import the Post model from apps1/models.py.
I am getting the following error:
ImportError at /
cannot import name Post
Traceback
admin.autodiscover()
<in file apps1/models.py>
from apps2.models import Blogs
<in file apps2/models.py>
from apps2.functions import get_blogs
<in file apps2/functions.py>
from apps1.models import Post
I thought it might be that the admin.autodiscover is importing the Post model first and then through an import loop, it is trying to import it again. Although I tried changing it to:
from apps1.models import Post as OtherPost
but that didn't help. Any idea why this is happening? Is it because there is a loop now?

If the only reason you import Blogs in apps1.models is that you have a relationship field in Post, how about using a lazy relationship instead? As far as I understand, those were designed specifically to deal with import loops like the one you're experiencing.
It is quite easy, instead of
from apps2.models import Blogs
...
class Post(models.Model):
...
my_blog = models.ForeignKey(Blogs)
you use something like this:
class Post(models.Model):
...
my_blog = models.ForeignKey("apps2.Blogs")

Related

Using multiple admin.py files for Django rest?

I currently have 2 admin.py files.
project/admin.py
project/pages/basicpage/admin.py
I would like to use the registered classes inside the second admin.py along with the first admin.py such that they can both be reached at the same admin endpoint.
FILE ONE: project/admin.py
from django.contrib import admin
from project import models
from project.pages.basicpage import admin as BP_admin
#admin.register(models.Test)
class TestAdmin(admin.ModelAdmin):
pass
FILE TWO: project/pages/basicpage/admin.py
from django.contrib import admin
from project import models
#admin.register(models.Platform)
class PlatformAdmin(admin.ModelAdmin):
pass
#admin.register(models.Type)
class TypeAdmin(admin.ModelAdmin):
pass
In file one, I have imported the second admin as BP_admin, not that it is used yet. However when I access my http://127.0.0.1:8000/admin endpoint, understandably I only can view the "Test" class that is registered in the first file. Any idea how to get my other 2 classes from my second file registered to the first file's endpoint?
Thanks!
Admin is just the models so importing the models should be enough. You can just add:
from project.pages.basicpage import models as BP_models
#admin.register(models.Test)
...
#admin.register(BP_models.Platform)
class Platform(models.Platform):
pass
You can also simplify and not use the class:
#admin.register(models.Test, BP_models.Platform,....)

Where in Django can I run startup code that requires models?

On Django startup I need to run some code that requires access to the database. I prefer to do this via models.
Here's what I currently have in apps.py:
from django.apps import AppConfig
from .models import KnowledgeBase
class Pqawv1Config(AppConfig):
name = 'pqawV1'
def ready(self):
to_load = KnowledgeBase.objects.order_by('-timestamp').first()
# Here should go the file loading code
However, this gives the following exception:
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
So is there a place in Django to run some startup code after the models are initialized?
The problem is that you import .models at the top of your file. This means that, when the file app.py file is loaded, Python will load the models.py file when it evalutes that line. But that is too early. You should let Django do the loading properly.
You can move the import in the def ready(self) method, such that the models.py file is imported when ready() is called by the Django framework, like:
from django.apps import AppConfig
class Pqawv1Config(AppConfig):
name = 'pqawV1'
def ready(self):
from .models import KnowledgeBase
to_load = KnowledgeBase.objects.order_by('-timestamp').first()
# Here should go the file loading code

Cannot import models from another app in Django

so I have 2 apps running in the same project.
My files are structured as follows:
/project_codebase
/project
__init.py
settings.py
urls.py
wsgi.py
...
/app1
...
/app2
...
manage.py
So, I for some weird reason have a different name for my base directory (that is, it ends with codebase). Hopefully, that is not an issue.
In my settings.py, I have this:
INSTALLED_APPS = [
...
'app1',
'app2',
]
Ok, so in my models.py (from app2), I can easily import models from app1 with from app1.models import *, however, when I use from app2.models import * in my models.py (from app1), I get an ImportError.
Any solutions to this?
This might be due to circular import issues. To avoid this you should load the model dynamically:
For recent versions of django (1.7+) use the application registry:
from django.apps import apps
MyModel1 = apps.get_model('app1', 'MyModel1')
For earlier django versions (<1.7):
from django.db.models.loading import get_model
MyModel1 = get_model('app1', 'MyModel1')
Note 1: If you want to define a ForeignKey relationship, there is no need for a separate import statement. Django has you covered on this:
If app1 is an installed app, you should define the ForeignKey relationship as follows:
# in app2.py
class MyModel2(models.Model):
mymodel1 = models.ForeignKey('app1.MyModel1')
Note 2: The get_model only works if app1 is an installed app and MyModel1 is the model you want to import from app1.
Note 3: Try to avoid wildcard import (from ... import *), as this is bad practice.
It's definitely a circular import.
But i think is what you need is to use models as some sort of RetationFields(ForeignKey, ManyToManyField or OneToOneField) arguments. So you need to skip import and use as so:
# app1/models.py
class Model1(models.Model):
relation_field = models.ForeignKey('app2.Model2')
From docs:
If you need to create a relationship on a model that has not yet been defined, you can use the name of the model, rather than the model object itself
To refer to models defined in another application, you can explicitly specify a model with the full application label
Just put str object as first argument to relation fields that leeds to <app_name>.<Model_name>.
Note: it's better to avoid importing everything from module(from <module_name> import *)
If you want to import only some specific module then do not use import *.
It will take more time load your all library and so can affect the speed of your app also.
If you want to use few modules from your second app then just add module name instead of whole libraries something like this:
from app2.models import Module1, Module2
or it may be circular import issue as other clarify.
Thanks.
i use this code always and it's work :)
from position_app.models import Member
You need to specify the model names you want to import, for ex from app1.models import ModelName1, ModelName2.
Make sure there is no name clash between one of your apps and one of the modules installed in your Python environment. If you use pip, you can run pip freezeto see a list of installed modules.
I had the same error when one of my apps was named 'packaging', and the packaging python module was installed.
I also face this problem when I try to import my model from another app in (django2.2)
But at last I Imported It and Its successfully working.
here is my two app:
INSTALLED_APPS = [
...
'categories',
'videos',
]
and this is the code for how I Imported it into videos/models.py file as a ForeignKey Connectivity
from django.db import models
class Videos(models.Model):
categories = models.ForeignKey('categories.Categories', related_name='categories', on_delete=models.CASCADE)
If want to see my Categories Model from categories/models.py file, you can check this code otherwise neglect it
from django.db import models
class Categories(models.Model):
category_name = models.CharField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
It is a circular import
In my case I needed the imported class not for a relation field, but for use it inside a method instead.
If that's the case, I suggest to import inside the method, otherwise an AppRegistryNotReady("Models aren't loaded yet.") is raised.
class Student(CustomUser):
""" Usuario alumno """
class Meta:
verbose_name = "Alumno"
verbose_name_plural = "Alumnos"
def get_current_school_class(self):
""" Obtiene el curso actual de un alumno """
from school.models import SchoolClass, StudentClass
# proceed with the method...
it's not necessary to import models from others apps
just put the app.models in the foreignkey field and that's work ;)
app 1:
class model1(models.Model):
field=models.field type ...
app 2:
class model2(models.Model):
field=models.ForeignKey('app1.model1', on_delete. ...)
to avoid code correction :D

Execute custom logic after Mezzanine form submission with page_processors.py

I have a question regarding page_processors.py. I've made a contact page with a form through the mezzanine admin and I have some logic that I'd like executed upon completion of that form. After reading the documentation, I found that creating a page_processors.py module in my app should help take care of that, but the file isn't being touched (ie, I can't get to the debugger inside it). Can anyone here help?
Here's my page_processors.py file:
from django import forms
from django.http import HttpResponseRedirect
from mezzanine.pages.page_processors import processor_for
from mezzanine.forms.models import Form
import requests
#do some testing to see that this code is correct
import pdb;pdb.set_trace()
#processor_for(slug="contact")
def form_view(request):
pass
Turns out you shouldn't name your app "site", interferes with an existing module named site (facepalm).

Help with Admin forms validation error

I am quite new to Django, I'm having few problems with validation
forms in Admin module, more specifically with raising exceptions in the
ModelForm. I can validate and manipulate data in clean methods but
cannot seem to raise any errors. Whenever I include any raise
statement I get this error "'NoneType' object has no attribute
'ValidationError'". When I remove the raise part everything works
fine.
Then if I reimport django.forms (inside clean method) with a different alias (e.g. from django import forms as blahbalh) then I'm able to raise messages using blahblah.ValidateException.
Any tips or suggestions on doing such a thing properly ?
Here's an example of what I'm doing in Admin.py:
admin.py
from django import forms
from proj.models import *
from django.contrib import admin
class FontAdminForm(forms.ModelForm):
class Meta:
model = Font
def clean_name(self):
return self.cleaned_data["name"].upper()
def clean_description(self):
desc = self.cleaned_data['description']
if desc and if len(desc) < 10:
raise forms.ValidationError('Description is too short.')
return desc
class FontAdmin(admin.ModelAdmin):
form = FontAdminForm
list_display = ['name', 'description']
admin.site.register(Font, FontAdmin)
--
Thanks,
A
You problem might be in the * import.
from proj.models import *
if proj.models contains any variable named forms (including some module import like "from django import forms), it could trounce your initial import of:
from django import forms
I would explicitly import from proj.models, e.g.
from proj.models import Font
If that doesn't work, see if there are any other variables name "forms" that could be messing with your scope.
You can use introspection to see what "forms" is. Inside your clean_description method:
print forms.__package__
My guess is it is not going to be "django" (or will return an error, indicating that it is definitely not django.forms).

Categories

Resources