I'm creating a django app as a python package , almost similar to django-tinymce
interesting point about django-tinymce is that every time I restart my web server , for example I run :
python manage.py runserver
somehow automatically a settings.py file inside django-tinymce start running.
how is this possible ?
I just add tinymce in the INSTALLED_APPS and nothing else but the code inside python2.7/site-packages/tinymce/settings.py starts running and do a few initialization operations every time I restart my web server or run any manage.py command.
Such initialisation code is often put in the models.py which is run by Django at start or restart.
In this example app it is just a matter of imports run - models.py imports widgets and widgets import settings.
As django 1.7 each app can contain an app.py file to do any initialization it needs to do.
Imagine we have a app called profile.In your app directory create an apps.py like this :
#apps.py
from django.apps import AppConfig
class ProfileConfig(AppConfig):
name = "profiles"
verbose_name = 'User Profiles'
def ready(self):
#do what ever you want
One more step to complete this behavior is to specify default_app_config
Which should happened in init.py of your app :
# profile/__init__.py
default_app_config = 'profile.apps.ProfileConfig'
This behavior can be used in many usecases including : changing project settings,registering signal handlers
More details can be found in Django 1.7 release notes and Django docs:Applications
Related
I am trying to create a custom python script within my Django application. This script requires the use of my app models. I am unable to figure out how to import the models appropriately to be used within this script.
My project directory:
-my_proj(name:ais)
-my_app(name:pages)
-__init__.py
-models.py
-urls.py
...
-utils
-__init__.py
-custom_script.py
So if I wanted to access the pages.models from the custom_script.py how might I do this?
I have attempted various imports such as from django.core.management import settings and from django.core.wsgi import get_wsgi_application but I still get an error stating the following:
ModuleNotFoundError: No module named 'pages'
There is a lot of app configuration done by Django to make your models and settings properly available. The best way to get Django to do this configuration is to make your script a management command, which will be run by python manage.py <your_script_name>. How to make your own management commands is covered by the docs. https://docs.djangoproject.com/en/3.2/howto/custom-management-commands/
I always use runscript for this, which is part of django-extensions. It requires installing this library, but it's well worth it. You can then create a scripts/ directory in your project root, and you'll have all your models available.
Simply
pip install django-extensions
and then follow the steps here
You can write a custom Command:
Add a management/commands directory to your app:
my_app/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
my_command.py
Then you can create the file my_app/management/commands/my_command.py, contains something like below:
from django.core.management.base import BaseCommand, CommandError
from my_ap.models import MyModel
class Command(BaseCommand):
help = 'Command to update some field'
def add_arguments(self, parser):
parser.add_argument('ids', nargs='+', type=int)
def handle(self, *args, **options):
for cur_id in options['ids']:
try:
obj = MyModel.objects.get(pk=my_id)
except MyModel.DoesNotExist:
raise CommandError('MyModel "%s" does not exist' % my_id)
obj.for_index = False
obj.save()
self.stdout.write(self.style.SUCCESS('Successfully closed "%s"' % my_id))
one way to see all of the models in your app is to import apps from django apps and use the get_models method.
from django.apps import apps
then you can use a comprehension in in order to view all of your models and their path. once you see the path you want you can import it at the top of your script.
models = { model.__name__: model for model in apps.get_models() }
input models into your shell to see the list of models in your app and the path from root
Also you make sure that you have import setup in your script
In the standard setup, Django applications are called by a WSGI server (like gunicorn and mod_wsgi) to answer HTTP requests, the entrypoint at user-level is the django View.
Can I make a custom entrypoint to call Django apps? If so, How I properly load a Django app?
Edit: Looking at the entrypoint in the wsgi.py file made by the startproject command, I see that 1) it sets the DJANGO_SETTINGS_MODULE var and calls get_wsgi_application which 2) calls django.setup() and 3) returns a WSGI application that will be called by the WSGI Server. 1 and 2 also happens when django's admin commands are ran. Is it enough to do 1 and 2 and have a properly loaded Django app? At 3 the django's middlewares are loaded, but they are not compatible, since I will not be doing HTTP calls (but the Django app will, of course, answer HTTP requests coming from other clients).
Is it enough to do 1 and 2 and have a properly loaded Django app?
Looking at Django's source code and this documentation, I figured out how to load a Django app. Taking as example the Django's intro tutorial, I could load the polls app and call its index view this way:
# Let Django knows where the project's settings is.
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
from django.apps import apps
# Load the needed apps
apps.populate(installed_apps=['polls.apps.PollsConfig'])
# Make sure the above apps were loaded
apps.check_apps_ready()
apps.check_models_ready()
# Call it
from polls.views import index
# Here index view is decoupled from Django's HTTP interface, so in polls/views.py you have:
# def index():
# return Question.objects.order_by('-pub_date')[:5]
print('index view: ' + str(index()))
It does not load any of the Django middlewares (they are coupled to the HTTP interface). The polls app does not depends on other installed apps, otherwise all dependencies should be loaded too.
I need to use a model from another python project to store data in django database. So, a create an another python file, which runs continuously, inside directory of other django files. The files structure are show bellow
ProjectFolder
WebSite
operation
urls.py
views.py
models.py
admin.py
apps.py
db.sqlite3
manage.py
pythonserver.py
In my pythonserver.py i try to do:
import os, sys
if os.environ.setdefault('DJANGO_SETTINGS_MODULE','WebSite.settings'):
from WebSite.operation.models import Registers
else:
raise
sys.exit(1)
The execution returns: "django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
I'm using django 1.11
What is wrong? What the best pratice to use a model from other python file/project?
Thanks a lot!
I found the answer
I django 1.11 it's necessary executes setup() method from django. Then the sintax is:
if os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'WebSite.settings'):
import django
django.setup()
from WebSite.operation.models import Registers
from django.utils import timezone
else:
raise
sys.exit(1)
I would like to create a User model that has an additional couple fields in django. I tried to do so by following the advice
https://stackoverflow.com/a/22696794/3426600 to create a custom user model
in models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
user_data = models.TextField(null=True)
In settings.py
AUTH_USER_MODEL = 'app_name.User'
but when I run python manage.py syncdb
I get the errors:
CommandError: One or more models did not validate:
account.emailaddress: 'user' has a relation with model app_name.User, which has either not been installed or is abstract.
admin.logentry: 'user' has a relation with model app_name.User, which has either not been installed or is abstract.
auth.user: Model has been swapped out for 'app_name.User' which has not been installed or is abstract.
socialaccount.socialaccount: 'user' has a relation with model app_name.User, which has either not been installed or is abstract.
Could I be using the wrong app_name? If so, where do I find the app_name?
How do I make the custom user work with socialaccount, etc?
Assume your project strucutre is something like below, and the codes of User(AbstractUser) are located in mysite/mysite/app1/models.py:
mysite/ (root folder for the project, put it anywhere in your disk. Most developers have a workspace folder(s) in computer)
(other non-application things. E.g. a static/, README.md, ...)
manage.py
mysite/ (container for all applications. You can put applications directly under root folder, but not recommended)
__init__.py
settings.py
urls.py
wsgi.py
app1/ (each application resides in its own folder. You don't want to put all models in one models.py file or all views in one view.py file, right?)
__init__.py
models.py
views.py
......
Then the app_name is app1, i.e. AUTH_USER_MODEL = 'app1.User'. Meanwhile, you need to add mysite.app1 into INSTALLED_APPS in settings.py. This probably will solve you CommandError issue.
ADDED NOTES:
Each application, you can consider it as a module of your project. The app_name of the application is the folder name. If you have defined models in one application, must add it into INSTALLED_APPS in settings.py.
Manually creating a folder is not a good way. django-admin.py startapp is more recommended, because it together creates some common files for an application, e.g. init.py, models.py, view.py, ...
Suggest you to go through the django quick-start guide, if you haven't done it: https://docs.djangoproject.com/en/dev/intro/tutorial01/
Base project structure
baseproject
baseapp
models.py
class BaseModel(models.Model)
...
Other project structure:
project
app
views.py
urls.py
project.app.views.py
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'
from django.conf import settings
from baseproject.baseapp.models import BaseModel
print BaseModel.objects.count()
it raised "Table 'project.baseapp_baemodel' doesn't exist" error when run from command line: "python views.py".
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'baseproject.settings'
from django.conf import settings
from baseproject.baseapp.models import BaseModel
print BaseModel.objects.count()
After changed project.settings to baseproject.settings, it works in command line.
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'baseproject.settings'
from django.conf import settings
from baseproject.baseapp.models import BaseModel
def someview(request):
count = BaseModel.objects.count()
return render_to_response(...)
But it still raised "Table 'project.baseapp_baemodel' doesn't exist" error when access the view by opening corresponding url in browser.
What's wrong in above code?
You are fighting against the framework here, and you'll be better off if you rethink your architecture. Django is built around the assumption that a project = a given set of INSTALLED_APPS, and the project settings name a database to which those apps are synced. It's not clear here what problem you have with just doing things that way, but whatever you're trying to achieve, it can be achieved without trying to import models from an app that is not in your current project's INSTALLED_APPS. That is never going to work reliably.
If there's an app you want in both projects, you should put it on your PYTHONPATH (or in virtualenvs) so both projects can access it, and put it in the INSTALLED_APPS of both projects. If you also need its data shared between the projects, you might be able to point both projects at the same database (though you'd need to be careful of other conflicting app names that you might not want to share data). Or you could use the multi-database support that's now in Django trunk to have the one project use the other project's database only for that one app.
My guess is if you back up a step and explain what you're trying to do, there are even better solutions available than those.