In one of my apps I have a file called lifecycle with types like so
TYPES = {
'viaf:personal': "986a7cc9-c0c1-4720-b344-853f08c136ab", # E21 Person
'viaf:corporate': "3fc436d0-26e7-472c-94de-0b712b66b3f3", # E40 Legal Body
'viaf:geographic': "dfc95f97-f128-42ae-b54c-ee40333eae8c" # E53 Place
}
I want to move them into my settings.py folder so that can be configurable from there. I am new to Django and am not sure how to go about this. What is the best way to go out doing so?
You can literally move that dictionary into your settings.py file and import it from whatever module you use it in:
from django.conf import settings
...
print(settings.TYPES['viaf:personal'])
After some research I decided that turning these into environment variables with default values was the easiest and safest option.
Related
hope I can express myself clearly here, bear with me..
Say I have a retail app that sells t-shirts. Each t-shirt can be in a pre-sale, or in-sale phase.
Each time a user goes to a particular t-shirt-page, I can compare the datetime now versus the datetime of when it goes on sale and determine whether it is pre-sale or in-sale and output the appropriate data/content.
Instead, I can have a "phase" string property on my t-shirt, initially set at "presale". I can then set a task queue to execute when the sale starts, and switch the "phase" property of the t-shirt from "presale" to "in-sale". When a user visits a t-shirt page, I check the string, whether it is "presale" or "insale" and output the appropriate data/content.
My question, is one method preferred over the other? I'd assume that the first method, which is a datetime calculation/comparison, would be less efficient than the 2nd method which is based on string comparison? However, the 2nd method requires the use of task queues which adds overhead/cost?
The first thing that comes to my mind is configuration. It's local, it's just reading a file, and it does not compare anything.
Okay, I'll use a structure I've used a lot on my Django and Flask projects. My folder structure usually look like this:
main/
-app/
|_ __init__.py
|_ app.py
-templates/
-settings/
|_ __init__.py
|_ settings.py
|_ settings.json
_ main.py
My settings.py file is where the variables are. It's value it's huge, but it's implementation is simple.
Let's see a example:
#settings.py
import json
path_of_json= "path here"
class Settings:
#Object interface of the settings
class _Product:
# Non-public class that implements a object interface for the products
def __init__(self,name,sale_status):
# Inicialization
self.name = name
self.sale_status = sale_status
def __init__(self):
#Handles what happens at initialization
global path_of_json
self.dict= self._load_json(path_of_json) #this dictionary will hold the data we load from the JSON
self.product1 = self._Product(self.dict['product1_name'],self.dict['product1_sale_status'])
#Here we use the data that were loaded from the JSON
self.product2 = self._Product(self.dict['product2_name'],self.dict['product2_sale_status'])
def _load_json(self):
#Here you implement the JSON loading
pass
That's our configuration file.
Now to the main app, and how to make this do something
#main.py
from settings.settings import Settings
my_settings = Settings()
product1 = { "name":my_settings.product1.name,"sale_status":my_settings.product1.sale_status}
#Here the product was loaded from the settings
#A lot of awesome code here
def render_product_page(product): #This function receives a dictionary
render_template("sale_status-insert how your template engine show fields here", product["name"])
That's how it's (kinda) done.
Now all that you need to implement is a little daemon that wakes each 24 hours, check the data on the settings.json file, and if it's outdated, update it. (This I'll leave for you XD)
Hope this helps :)
Let's say I have the following settings.py:
LOCALE_PATHS = (
'/conf/locale'
)
DEBUG = True
Can I read value of DEBUG from my python code?
Can I get full path to my language file (django.mo) django uses taken into consideration my LOCALE_PATHS value?
Yes, you can import settings and look for your values:
from django.conf import settings
print settings.DEBUG
Included in a separate comment was the following from LA_:
"Thanks, Joseph. If I print settings.LOCALE_PATHS, it prints exactly the value I defined. How could I get the full path django uses?"
What may be useful for you to do is record the absolute path by using the os.path module.
For example, you could do the following:
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
LOCALE_ABS_PATH = os.path.join(PROJECT_PATH, LOCALE_PATHS[0])
Then you could reference LOCALE_ABS_PATH as the absolute path to the LOCALE_DIRS listed in settings.py
Let me know if this is helpful at all. I'm not entirely sure of the context with which you plan to implement that, but perhaps I could help more if you continue to have trouble.
I was wondering if it were possible, and preferably not too difficult, to use Django DiscoverRunner to delete my media directory between every test, including once at the very beginning and once at the very end. I was particularly interested in the new attributes "test_suite" and "test_runner" that were introduced in Django 1.7 and was wondering if they would make this task easier.
I was also wondering how I can make the test specific MEDIA_ROOT a temporary file, currently I have a regular MEDIA_ROOT called "media" and a testing MEDIA_ROOT called "media_test" and I use rmtree in setup and tearDown of every test class that involves the media directory. The way I specify which MEDIA_ROOT to use is in my test.py settings file, currenly I just have:
MEDIA_ROOT = normpath(join(DJANGO_ROOT, 'media_test'))
Is there a way I can set MEDIA_ROOT to a temporary directory named "media" instead?
This question is a bit old, my answer is from Django 2.0 and Python 3.6.6 or later. Although I think the technique works on older versions too, YMMV.
I think this is a much more important question than it gets credit for! When you write good tests, its only a matter of time before you need to whip up test files, or generate test files. Either way, your in danger of polluting the File System of your server or developer machine. Neither is desirable!
I think the write up on this page is a best-practice. I'll copy/paste the code snippet below if you don't care about the reasoning (more notes afterwards):
----
First, let’s write a basic, really basic, model
from django.db import models
class Picture(models.Model):
picture = models.ImageField()
Then, let’s write a really, really basic, test.
from PIL import Image
import tempfile
from django.test import TestCase
from .models import Picture
from django.test import override_settings
def get_temporary_image(temp_file):
size = (200, 200)
color = (255, 0, 0, 0)
image = Image.new("RGBA", size, color)
image.save(temp_file, 'jpeg')
return temp_file
class PictureDummyTest(TestCase):
#override_settings(MEDIA_ROOT=tempfile.TemporaryDirectory(prefix='mediatest').name)
def test_dummy_test(self):
temp_file = tempfile.NamedTemporaryFile()
test_image = get_temporary_image(temp_file)
#test_image.seek(0)
picture = Picture.objects.create(picture=test_image.name)
print "It Worked!, ", picture.picture
self.assertEqual(len(Picture.objects.all()), 1)
----
I made one important change to the code snippet: TemporaryDirectory().name. The original snippet used gettempdir(). The TemporaryDirectory function creates a new folder with a system generated name every time its called. That folder will be removed by the OS - but we don't know when! This way, we get a new folder each run, so no chance of name conflicts. Note I had to add the .name element to get the name of the generated folder, since MEDIA_ROOT has to be a string. Finaly, I added prefix='mediatest' so all the generated folders are easy to identify in case I want to clean them up in a script.
Also potentially useful to you, is how the settings over-ride can be easy applied to a test class, not just one test function. See this page for details.
Also note in the comments after this article some people show an even easier way to get a temp file name without worrying about media settings using NamedTemporaryFile (only valid for tests that don't use Media settings!).
The answer by Richard Cooke works but leaves the temporary directories lingering in the file system, at least on Python 3.7 and Django 2.2. This can be avoided by using a combination of setUpClass, tearUpClass and overriding the settings in the test methods. For example:
import tempfile
class ExampleTestCase(TestCase):
temporary_dir = None
#classmethod
def setUpClass(cls):
cls.temporary_dir = tempfile.TemporaryDirectory()
super(ExampleTestCase, cls).setUpClass()
#classmethod
def tearDownClass(cls):
cls.temporary_dir = None
super(ExampleTestCase, cls).tearDownClass()
def test_example(self):
with self.settings(MEDIA_ROOT=self.temporary_dir.name):
# perform a test
pass
This way the temporary files are removed right away you don't need to worry about the name of the temporary directory either. (Of course, if you want you can still use the prefix argument in calling tempfile.TemporaryDirectory)
One solution I have found that works is to simply delete it in setUp / tearDown, I would prefer finding some way to make it automatically apply to all tests instead of having to put the logic in every test file that involves media, but I have not figured out how to do that yet.
The code I use is:
from shutil import rmtree
from django.conf import settings
from django.test import TestCase
class MyTests(TestCase):
def setUp(self):
rmtree(settings.MEDIA_ROOT, ignore_errors=True)
def tearDown(self):
rmtree(settings.MEDIA_ROOT, ignore_errors=True)
The reason I do it in both setUp and tearDown is because if I only have it in setUp I might end up with a lingering media_test directory, and even though it won't be checked in to GitHub by accident (it's in the .gitignore) it still takes up unnecessary space in my project explorer and I just prefer not having it sit there taking up space. If I only have it in tearDown then I risk causing problems if I quit out of the tests part way through and it tries to run a test that involves media while the media from the terminated test still lingers.
Something like that?
TESTING_MODE = True
...
MEDIA_ROOT = os.path.join(DJANGO_ROOT, 'media_test' if TESTING_MODE else 'media')
The Django docs say that I can call settings.configure instead of having a DJANGO_SETTINGS_MODULE. I would like my website's project to do this. In what file should I put the call to settings.configure so that my settings will get configured at the right time?
Edit in response to Daniel Roseman's comment:
The reason I want to do this is that settings.configure lets you pass in the settings variables as a kwargs dict, e.g. {'INSTALLED_APPS': ..., 'TEMPLATE_DIRS': ..., ...}. This would allow my app's users to specify their settings in a dict, then pass that dict to a function in my app that augments it with certain settings necessary to make my app work, e.g. adding entries to INSTALLED_APPS.
What I envision looks like this. Let's call my app "rexe_app". In wsgi.py, my app's users would do:
import rexe_app
my_settings = {'INSTALLED_APPS': ('a','b'), ...}
updated_settings = rexe_app.augment_settings(my_settings)
# now updated_settings is {'INSTALLED_APPS': ('a','b','c'), 'SESSION_SAVE_EVERY_REQUEST': True, ...}
settings.configure(**updated_settings)
Its not quite equivalent, since settings DJANGO_SETTINGS_MODULE updates defaults, found in django.conf.settings.global_settings, while parameter for configure completely ignores them, so you have to add some additional processing.
Beware, first, that you can't modify INSTALLED_APPS on the fly, as they are examined once on settings processing. For example, to apply modifications to INSTALLED_APPS in Apache-deployed application, you need to restart Apache.
Second, as settings are imported, therefore this point is prone to injections of some sorts, and is highly vulnerable to expose them to users.
If this is a meta app, there are two possibilities:
If you want to provide default settings for `django`-wise setting, add following to `default_settings.py` in your app:
INSTALLED_APPS = ('default_app', )
Just make sure you don't import `default_settings.py` in your app, and make your users add to their settings.py
from rexe_app.default_settings import *
INSTALLED_APPS += ('users_app', )
that effectively will set `INSTALLED_APPS` to `('default_app', 'users_app', )` for your end users.
In case you need `rexe_app`-wise settings, you can default them in your app's `__init__.py`:
from django.conf import settings
REXE_APP_CONFIG_PARAM = getattr(settings, 'REXE_APP_CONFIG_PARAM',
'default_param_value')
so when user needs to change default `REXE_APP_CONFIG_PARAM` he needs to just add
INSTALLED_APPS = ('rexe_app')
REXE_APP_CONFIG_PARAM = 'user_param_value'
to his `settings.py`.
It would be in your wsgi script. please have look at the docs.
You could run mysite.settings.configure() instead of os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
If you are using wsgi then call that in your wsgi script before running the app.
If you want to do this for dev server, pass it as command line option (mentioned on the same page).
django-admin.py runserver --settings=mysite.settings
Let's say I have a settings.py file in my app's root folder (/myapp/myapp/settings.py) with just a bunch of variables in it:
var1 = ''
var2 = ''
Can I automatically set one of those variables from the .ini file? I tried this:
myapp.settings.var1 = 'this is from development.ini'
But when I call var1 it is still the empty string:
import myapp.settings as s
print s.var1
I know that I can do var1 = config.get('myapp.settings.var1') in settings.py but that just doesn't seem as elegant to me :).
You can find relevant information at this page:
Getting Data from the Configuration File
.ini is one way only communication. Django uses settings.py which is a normal python module that can be manipulated on-the-fly (causing many obscure errors). Setup your settings in .ini and use config.get to access variables.