I am confused about the second answer in this post:
What is the most efficent way to store a list in the Django models?
For the custom field SeparatedValuesField, which directory I should put this py so I can import from custom.fields?
That answer assumes that you have a Python file named fields.py in a package named custom under your project root. ie:
/project root
---manage.py
---/custom
------__init__.py
------fields.py
You can put your fields.py under any existing app and import from that location. For example, if you have an app called myapp, you can put the fields.py under that package and rewrite your import statement as:
from myapp.fields import SeparatedValuesField
Related
Having a quite large models.py file (which contains several models), I'm trying to refactor, with one model per file.
I'm therefore trying to create a models package, with the following structure:
app/models/__init__.py
app/models/first_model.py
app/models/second_model.py
Unfortunately, I cannot get Django lazy reference mechanism to work well, i.e.:
first_model = models.ForeignKey('app.FirstModel')
returns the error that Django cannot find the model.
Any idea? Thanks!
It should work, make sure that in __init__.py you are importing all the models from first_model.py and second_model.py.
from .first_model import FirstModel
from .second_model import SecondModel
EDIT: If you want to retrieve the models as 'app_label.model_name', then you will have to import them in __init__.py, otherwise you can try the following:
Use https://docs.djangoproject.com/en/2.0/ref/applications/#django.apps.apps.get_model
Or you can use ContentTypes: https://docs.djangoproject.com/en/2.0/ref/contrib/contenttypes/#methods-on-contenttype-instances
The presence of __init__.py tells Python to consider it as a Package, but in order to let Django find your models for Migration and find it well, you should import all your models stuff in __init__.py
Keep the structure like it was:
app/models/__init__.py
app/models/first_model.py
app/models/second_model.py
__init__.py
from .first_models import *
from .second_models import *
In the Cookbook there is an example using only the name of the class (model) and not the app part:
first_model = models.ForeignKey('FirstModel')
I have something like this in one of my apps's models.py :
class Account(AbstractBaseUser):
email = models.EmailField(unique=True)
I want to import a class from another app's views.py as below:
from anotherapp.views import MyClass
The problem is in the first lines of anotherapp.views file, I imported the Account class. So when I want to import MyClass into my models.py file, this error raises :
ImportError: cannot import name Account
That is circular import error you are encountering. While it is bad practice to import from views to models in Django, if you still want to, you can follow methods in this question to resolve it.
Here are few alternative ways that can be considered as good practice:
You can consider importing other low-level modules exist within anotherapp instead of MyClass (not depending on views.py)
You can use Django's signals to catch anotherapp's events project wide and act according to.
You can create a third file, say utils.py in anotherapp, move MyClass there and let anotherapp/views.py and your app's models.py import from anotherapp.utils
I have shortcut function declared in __init__.py of my module in order to simplify importing it, ie.
from app.logger import log
instead of:
from app.logger.shortcuts import log
This function is a class object in principle, intendet to be used like singleton in this way:
# __init_.py
from app.logger.backends import LogDatabaseBackend
log = LogDatabaseBackend()
In the backends.py i need to import some models in this way:
# backends.py
from app.logger.models import Model1, Model2
class LogDatabaseBackend(object):
...
These models are necessary in some methods of LogDatabaseBackend. The problem is that Django show warnings like:
"RemovedInDjango19Warning: Model class app.logger.models.Model1 doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9."
I think the reason is importing model in init, before app was loaded. How should I change my code to avoid these warnings and maintain Django 1.9 compatibility?
Define application configuration in <app_name>.apps.py :
From Application Configuration documentation :
Application configuration objects store metadata for an application.
Some attributes can be configured in AppConfig subclasses. Others are
set by Django and read-only.
Here is an example from the documentation :
# rock_n_roll/apps.py
from django.apps import AppConfig
class RockNRollConfig(AppConfig):
name = 'rock_n_roll'
verbose_name = "Rock ’n’ roll"
You can make your application load this AppConfig subclass by default as
follows:
# rock_n_roll/__init__.py
default_app_config = 'rock_n_roll.apps.RockNRollConfig'
That will cause RockNRollConfig to be used when INSTALLED_APPS just
contains 'rock_n_roll'. This allows you to make use of AppConfig
features without requiring your users to update their INSTALLED_APPS
setting. Besides this use case, it’s best to avoid using
default_app_config and instead specify the app config class in
INSTALLED_APPS as described next.
If Model1 and Model2 are used with ForeignKey, you don't need to import them. Instead use ForeignKey("app.Model1", ...). This delays the import till after app registry. Otherwise, consider using function-level import.
Ok, so I'm trying to change this:
app/
- lib.py
- models.py
- blah.py
Into this:
app/
- __init__.py
- lib.py
- models/
- __init__.py
- user.py
- account.py
- banana.py
- blah.py
And still be able to import my models using from app.models import User rather than having to change it to from app.models.user import User all over the place. Basically, I want everything to treat the package as a single module, but be able to navigate the code in separate files for development ease.
The reason I can't do something like add for file in __all__: from file import * into init.py is I have circular references between the model files. A fix I don't want is to import those models from within the functions that use them. But that's super ugly. Let me give you an example:
user.py
...
from app.models import Banana
...
banana.py
...
from app.models import User
...
I wrote a quick pre-processing script that grabs all the files, re-writes them to put imports at the top, and puts it into models.py, but that's hardly an improvement, since now my stack traces don't show the line number I actually need to change.
Any ideas? I always though init was probably magical but now that I dig into it, I can't find anything that lets me provide myself this really simple convenience.
It depends on what your circular references are for. If you have a class in user that inherits from Banana and a class in banana that inherits from User, you can't do this. You also can't do it if each class defines a decorator that gets used in the other or anything else that gets called during the actual import.
You can, however, if you are just mutually referencing helper functions, or if your User object has a method to create new instances of Banana and your Banana object has a method that creates new instances of User. As long as the mutual reference doesn't actually get used until something in the module is called from outside it, then in your model folder, in __init__.py, you can just do something like:
import user
import banana
#etc...
user.banana = banana
banana.user = user
#etc...
User = user.User
Banana = banana.Banana
Then for sake of clarity and not trying to figure out what's going on
Dilemma
My views.py gets pretty unwieldy, so I want to separate it into a separate views module inside of my app. However, I'm not sure this is a good idea, for two reasons:
If my views file is the same name as the app name, I cannot import the model without using django.db.get_model, therefore I am worried my approach may be flawed. I have heard it is best practice to avoid name collision within modules; should I rename my view files?
I'm not sure if creating a views module is considered good practice within the Django community in general.
Example
For example, for an app named blogs, with a Blog model and a Post model:
blogs/
__init__.py
models.py
urls.py
views/
__init__.py
blogs.py
posts.py
Here is my blogs.views.blogs:
# project/blogs/views/blogs.py
from django.db.models import get_model
from django.shortcuts import get_object_or_404
from django.views.generic import ListView, DetailView
# Cannot import model directly, results in `ImportError: No module named models`.
# This can be resolved if I resolve the name collision between this file and
# the app itself.
#
# from blogs.models import Blog
class BlogListView(ListView):
model = get_model('blogs', 'Blog')
def get_queryset(self):
return self.model.objects.all()
class BlogDetailView(DetailView):
model = get_model('blogs', 'Blog')
def get_object(self):
blog_pk = self.kwargs.get('blog_pk')
return get_object_or_404(self.model.objects, pk=blog_pk)
Question
My question is twofold:
Should I be separating my views in the first place?
If so, is using get_model a good idea, or is there a way I can import my model directly without using this method? Or should I change my view file names, for example by adding the suffix _views (e.g.: blogs.views.blogs_views.py) in order to avoid the problem altogether?
I cannot import the model without using django.db.get_model
You can: from project_name.app_name.models import MyModel And it's preferable way, 'relative imports for intra-package imports are highly discouraged', - as said in PEP-8.
There shouldn't be any problems with names, views.py has no special meaning in Django, it's just a convention.
You can keep your views in any file in any module under any name you want. So there is no special rules here, if you think that separating the module into submodules will be good, do it.
As DrTyrsa points out, views has no special meaning. So as an alternative to creating a subpackage, you could just create several files at the same level as the existing views.py - blog_views.py, posts_views.py, etc. As long as you use the correct reference in urls.py, this works fine.