Cyclic imports within django subapps - python

I'm working on a django project where i have the following setup
project
/products
/product1
/models.py
/forms.py
/productN
/otherapps
#models.py
from .forms import foo
...
#forms.py
from .models import bar
You see the cyclic imports. I've tried a number of combinations but i cant seem to get it right. I'd rather not move the code in forms.py to models.py
I've tried:
from products import *
from products.product1 import *
from products.product1.form import *
import products
import products.product1
import products.product1.form
Some help would be much appreciated.

In models.py move your
from .forms import foo
to inside the method that actually needs to use foo. This will stop it from importing until that method is called rather than as soon as models.py is imported. This isn't best practise and if you use foo in lots of places then it will be a pain to maintain but it should fix the circular import.

Related

In Django, why i cannot import a model in an python file created by me in inside the same app?

I created in Django, in my app an python file for forms and I want to import a model from .models (from the same app).
The problem is when I import the model, it returned an error.
The model is(models.py):
class Article(models.Model):
title = models.CharField(max_length=100)
location=models.CharField(max_length=120,null=True,blank=True)
category=models.CharField(max_length=100,null=True,blank=False)
slug=models.SlugField(null=True, blank=True, unique=True)
boddy=models.TextField()
timestamp = datetime.now()
update = models.TimeField(auto_now=True)
The problem is in util.py (the python file that i created) :
from .models import Article
The error is:
ImportError: cannot import name 'Article' from partially initialized module 'hello.models' (most likely due to a circular import) (D:\Python\Django\Projects\myproject\hello\models.py)
The python files are in the same app
It seems you're trying to do what is called a 'Circular Import'; you can't do that.
Your App is separated in modules and packages. (.py files and folders with a __init__.py file inside), and when you import a module into another module, python will run that entire module and set it into memory.
If in models.py you run
from ./.. import utils
... and in utils.py
from .models import Article
You will end up importing a module into another then into another recursively, resulting in a Memory Overflow.
To prevent that from happening, Django comes with a few checks that prevent that circular import.
A good way to prevent that is to separate your classes into smaller modules, so you only import that module.
On the other hand, if you're to refer to Foreign Keys, you can use Django built-in Lazy Reference by using '<app_name>.<ClassName>' under quotes.
By doing so, you don't have to import the module, hence, there's no risk of circular import.

What are the tricks about importing modules?

I am working on a django project. In views.py I invoked a function from custom.py . The problem is it is working nicely. But I didn't write something like:
from .custom import *
or
import custom
In a sentence, there is not the the word 'custom' anywhere in views.py.
Why it's working? Is there any other way to import module that i don't know about? What is it?
Or any kind of django trick?
addition:
The custom.py also did not import views.py
custom.py has imported models.py
It's possible that your views.py file is importing from another module which imports the function you are using.
models.py
from .custom import my_function
views.py
from .models import *
# my_function will be available
This occurs because the import * statement imports all functions and classes, including anything that has already been imported into that module. There is some information about it in the python docs.
You can avoid this by only importing the specific functions and classes you need, eg:
views.py
from .models import PersonModel, ProductModel

Attempted relative import beyond toplevel package in django

the code is not been working due to the error in assigning the path properly please help me with that.
Try this in your models:
#Remove the import statement: from blog.models import sighinmodel
#Then, inside your model
user = models.ForeignKey('blog.sighinmodel' , on_delete = None)
Also, I would like to point out that this is not the correct way of importing other modules in your models.py .
You should do like this:
from appname.models import ModelName
#for importing from another module's models.
There is no need for relative path names in import statements in Django. from appname.module import function/class works fine for nearly all the cases until cyclic redundancy occurs, in which you have to take one among many methods. One is the way I mentioned above:
Method 1: Simply put this inside the ModelClass. Don't import anything.
user = models.ForeignKey('blog.sighinmodel' , on_delete = None)
Method 2(when cyclic import condition is not arising)
from blog.models import sighinmodel
class SomeModel(models.Model):
user = models.ForeignKey(sighinmodel , on_delete = None)
NOTE: The above will work only if a cyclic import isn't occurring. In case the cyclic import condition is occurring, switch back to the first method of declaration.
Hope this helps. Thanks.
This error is coming because relative imports are not allowed beyond top level package. Your blog is itself a module so if you import your model from there it would work.
from blog.models import User, sighinmodel
I would also suggest you to use CamelCase for your models name since they are classes for naming conventions.

Python manage classes in separate files

I have a project which uses the MVC pattern.
In folder "models" I have quite many classes, each class is now has its own file. But I feel like it's not convenient, because every time I need to use a class I have to import it separately. E.g. I have many of the followings in my app source:
from models.classX import classX
from models.classY import classY
If I want to import everything at once, something like from models import * I found that I can put all sorts of import in models/__init__.py. But is it the pythonic way to do it ? What is the convention ?
Python is not java; please avoid the one-file-per-class pattern. If you can't change it, you can import all of them from a submodule of your models package:
# all.py: convenient import of all the needed classes
from models.classX import classX
from models.classY import classY
...
Then in your code you can write:
import my.package.models.all as models # or from my.package.models.all import *
and proceed to use models.classX, models.classY, etc.
Most pythonic way is one that you're already using. You can alleviate importing by grouping your classes in modules. For example, in Django usually all application models are in a single file.
From python docs:
Although certain modules are designed to export only names that follow certain patterns when you use import *, it is still considered bad practise in production code.
Firstly, you should rename your classes and modules so that they don't match, and follow PEP8:
models/
classx.py
class ClassX
classy.py
class ClassY
Then, I'd got with this in models/__init__.py:
from models.classx import ClassX
from models.classy import ClassY
Meaning in your main code, you can do any one of:
from models import *
x = ClassX()
from models import ClassX
x = ClassX()
import models
x = models.ClassX()

Why would I put code in __init__.py files?

I am looking for what type of code would I put in __init__.py files and what are the best practices related to this. Or, is it a bad practice in general ?
Any reference to known documents that explain this is also very much appreciated.
Libraries and frameworks usually use initialization code in __init__.py files to neatly hide internal structure and provide a uniform interface to the user.
Let's take the example of Django forms module. Various functions and classes in forms module are defined in different files based on their classification.
forms/
__init__.py
extras/
...
fields.py
forms.py
widgets.py
...
Now if you were to create a form, you would have to know in which file each function is defined and your code to create a contact form will have to look something like this (which is incovenient and ugly).
class CommentForm(forms.forms.Form):
name = forms.fields.CharField()
url = forms.fields.URLField()
comment = forms.fields.CharField(widget=forms.widgets.Textarea)
Instead, in Django you can just refer to various widgets, forms, fields etc. directly from the forms namespace.
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField(widget=forms.Textarea)
How is this possible? To make this possible, Django adds the following statement to forms/__init__.py file which import all the widgets, forms, fields etc. into the forms namespace.
from widgets import *
from fields import *
from forms import *
from models import *
As you can see, this simplifies your life when creating the forms because now you don't have to worry about in where each function/class is defined and just use all of these directly from forms namespace. This is just one example but you can see examples like these in other frameworks and libraries.
One of the best practices in that area is to import all needed classes from your library (look at mongoengine, for example). So, a user of your library can do this:
from coollibrary import OneClass, SecondClass
instead of
from coollibrary.package import OneClass
from coollibrary.anotherpackage import SecondClass
Also, good practice is include in __init__.py version constant
For convenience: The other users will not need to know your functions' exactly location.
your_package/
__init__.py
file1.py/
file2.py/
...
fileN.py
# in __init__.py
from file1 import *
from file2 import *
...
from fileN import *
# in file1.py
def add():
pass
then others can call add() by
from your_package import add
without knowing file1, like
from your_package.file1 import add
Put something for initializing. For example, the logging(this should put in the top level):
import logging.config
logging.config.dictConfig(Your_logging_config)

Categories

Resources