I have a Django app with some management commands. In one of those commands, I need to write a log file which is located in /logs allong side views.py, models.py, etc ...
Considering that my management command script is in /management/commands/mycommand.py, is there any reliable way to determine the location of the appdir from within mycommand.py ?
PS: by reliable, I mean without using os.path.abspath( __file__ ), because the location of the file might change later on.
That's what your settings are for.
Add this to your settings
MY_APP_LOG_DIRECTORY = "path/to/logs"
In your view functions, use
from django.conf import settings
Now you can use settings.MY_APP_LOG_DIRECTORY all you want.
Related
I want to use a Django model in an external python script. This python script is placed within the root directory of my project and I also created an init.py module for easy importing. Can anyone please instruct on what is the most secure and efficient way of importing a Django model into the python script?
I would also appreciate it if someone could advise me whether or not it is accurate to place an init.py module within the root directory. If not, what is the best way of doing this?
use this solution only if you want your scripts to be standalone (you want to access models when server is not running)
There are basically two different ways to do that:
If you are going to run this code frequently, I strongly suggest that you create a management command for the code. (check instructions here)
But if it's a bulk-data-import or something that's not gonna run many times, you can use something like this (put this in the root of your django app - beside manage.py):
import os
import django
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<your_project_name>.settings")
django.setup()
# now you have access to your models
# as an example:
# from users.models import User
#
# for user in User.objects.all():
# print(user)
also keep in mind that you should always import your models after django.setup(), otherwise, you'll get an error.
I would also appreciate it if someone could advise me whether or not it is accurate to place an init.py module within the root directory. If not, what is the best way of doing this?
If you want to have multiple script files, it's not a good idea to put them in the root of django project. You can create a python package, say my_scripts, beside manage.py and put your scripts there.
So you will end up with something like this:
...
manage.py
my_scripts
├── __init__.py
└── first_script.py
But now you need to make a little change in the script file to make it work correctly. You should append the BASE_DIR to your path so that python can recognize the settings file (or module, if you extend it):
import os
import sys
import django
if __name__ == '__main__':
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<your_project_name>.settings")
django.setup()
# now you have access to your models
# as an example:
# from users.models import User
#
# for user in User.objects.all():
# print(user)
I have my project settings in settings.py file. There are database names, user names, host names etc. defined there. In project files I do import settings and then use the constants where needed like settings.HOST. For unit testing I would like to use different settings. How should I override the settings? I am not using django.
You could create a new file - say local_settings.py in which you override the specific settings for you debugging and testing purposes.
Then you add this block at the end of your settings.py
# Override these settings with local settings if such a file exists
try:
from local_settings import *
except ImportError as e:
pass
You should add local_settings.py to your .gitignore file to exclude this file from version control (if you are using git).
This is the standard way Django does this by the way.
I suppose the easiest way would be to move your settings.py to another folder for safekeeping and then make a new one, and edit that for debugging.
Let's have a django project using a 3rd party application.
I'd like to override some of its modules without touching original files.
Simple subclassing is not possible here, need to override code transparently as many other apps rely on original class names and functions.
Project's structure looks like:
django_project/
__init__.py
settings.py
overrides/ <-- here is a subdir with apps overrides
__init__.py
payment/ <-- here is an example of app to override
__init__.py
admin.py
forms.py <-- this file is ignored, original is imported
models.py
tests.py
views.py
settings.py was modified with
INSTALLED_APPS=(
'satchmo_store.shop'
#'payment' # original values
'overrides.payment' # modified app
...
)
The above solution however does not work, because Django does not insert path of added app into modules search path (sys.path).
Django just loads admin.py, models.py, tests.py and views.py, other files like forms.py are ignored.
Is this behaviour documented somewhere ? What exactly placing a module name in INSTALLED_APPS does behind scenes ?
I hacked the situation with hardcoding new modules search path in manage.py and Apache's setting of WSGIPythonPath.
import os.path
import sys
DIRNAME = os.path.dirname(__file__)
APPS_OVERRIDE = os.path.join(DIRNAME, 'overrides')
if not APPS_OVERRIDE in sys.path:
sys.path.insert(1, APPS_OVERRIDE)
I doubt this is the right way. Cann't find a guide describing apps overriding.
So, how can I properly override external Django application in my project ?
The bonus question: Do I need to copy whole application directory tree, not just particular files which are really modified ? As far as I know, Python stops at first matching module path, so it won't import other modules available in following parts of the search path.
Example of how to override your form:
overrides/payment/forms.py
from django import forms
class YourNewFormThingy(forms.Form): pass
overrides/payment/models.py
from satchmo.payment import forms as satchmo_payment_forms
from . import forms
satchmo_payment_forms.SomeForm = forms.YourNewFormThingy
Try including payment as well along with override.payment as satchmo uses payment module to process payments and payment code is flexible enough to include your code as well.
I'm making a very very reusable CMS in Django. I'm trying not to hardcode anything, so I want a config.py or something for the app itself.
I want to use it in templates (something like {{ config.SITE_NAME }}) and just regular Python code (views, models), etc.
How would I go about doing that?
Django already has the settings.py file and an interface to use the values from there, is that not good enough? Accessing settings in your code is easy:
from django.conf import settings
do_something_with(settings.MY_CONFIG_VARIABLE)
In your template it requires a bit more work, like making a context processor for example. This answer shows you have to make a context processor that exposes values from settings to your template.
settings.py serves this purpose already in django. You can add custom settings to it for your application.
https://docs.djangoproject.com/en/dev/topics/settings/#using-settings-in-python-code
When you create a django project, it automatically creates a settings.py file. Put your settings in that file, and then :-
from django.conf import settings
settings.YOUR_SETTING
also, if you have some settings, that will vary depending upon the machines (eg. production/test servers).
Then just add eg. conf/local_settings.py file and put the machine specific settings in that file, and in settings.py just do :-
from conf.local_settings import *
at the end of settings.py
Make sure you ignore local_settings.py from your VCS check-in (eg. in case of git add local_settings.py to .gitignore
I am relatively new to Django and one thing that has been on my mind is changing the database that will be used when running the project.
By default, the DATABASES 'default' is used to run my test project. But in the future, I want to be able to define a 'production' DATABASES configuration and have it use that instead.
In a production environment, I won't be able to "manage.py runserver" so I can't really set the settings.
I read a little bit about "routing" the database to use another database, but is there an easier way so that I won't need to create a new router every time I have another database I want to use (e.g. I can have test database, production database, and development database)?
You can just use a different settings.py in your production environment.
Or - which is a bit cleaner - you might want to create a file settings_local.py next to settings.py where you define a couple of settings that are specific for the current machine (like DEBUG, DATABASES, MEDIA_ROOT etc.) and do a from settings_local import * at the beginning of your generic settings.py file. Of course settings.py must not overwrite these imported settings.
Why you need a test database? Django create test database automatically before running unittest. And, database routing is not fit your purpose, it's for routing you read/write requests to different database. If you want to use a development database, set up a new DATABASE config in, say local_settings.py, and at the last of your settings.py, type
try:
from local_settings import *
except ImportError:
pass
There is nothing you can specify in the settings directly. The practice I use is to have addtional setting files for different environments which contain just the settings overwritten which I want to change, like database settings or cache settings for example. My project root application for example would contain the following files on a development environment (attention to the leading underscore):
...
settings.py
settings_dev.py
_settings_test.py
_settings_prod.py
...
Then in settings.py I would add the following lines of code to the beginning:
try:
from settings_prod import *
except ImportError:
try:
from settings_test import *
except ImportError:
from settings_dev import *
Since I am on dev environment it will only import my settings_dev file, since the others have a leading underscore.
When I deploy then to a production or testing environment I would rename the relevant files. For production: _settings_prod.py -> settings_prod.py, for testing: _settings_test.py -> settings_test.py. settings_dev.py can basically stay as is, since it will be only imported if the other two fail.
The last step you could simply do with automated deployment via fabric or other tools. An example with fabric would be something like run('mv _settings_prod.py settings_prod.py') for renaming.