Has Django version 3 stoped the need to register new apps in settings.py installed apps list? - django

The apps i create are working with out any need for them to be registered in settings.py of the project.
The official documentation also doesn't register its polls app in INSTALLED_APPS. https://docs.djangoproject.com/en/3.0/intro/tutorial01/
What is the use of registering apps in INSTALLED_APPS of settings.py if it works with out registering?

In python, anything you import is known to the code where it is imported, but the inverse is not possible...
Imagine I have two files
# a.py
def foo():
...
# b.py
from a import foo
def bar():
foo()
In b.py I know about foo, but a.py doesn't know about bar or even that b.py exists.
Now when you have a router, you import your views which import models, etc. Your full app can work with this. But for Django to know about your app it needs at least some reference to it. The INSTALLED_APPS in settings tells Django which apps are meant to be part of your entire Django project. By default, it includes some Django apps. Not every project needs all of them so some (or all) might be removed. Similarly, other 3rd party apps might be added.
Running Django management commands such as migrate or collectstatic will only work on apps included in INSTALLED_APPS.
P.S: Never access INSTALLED_APPS in your code, but rather use the app registry via from django.apps import apps

Related

Django single-test migration

I have recently implemented a reusable app within the django project I am working on. For the sake of the question, let's call it reusable_app. This app also has some unittests that run, however, these tests depend on some basic models declared somewhere next to the tests in a model.py.
/resuable_app
__init__.py
models.py
views.py
urls.py
/tests
__init__.py
tests.py
/simple_app
__init__.py
models.py
Now, the models aren't loaded in the database unless I specify the folder in INSTALLED_APPS in the testing configuration file. I was wondering if there is another way to achieve this, not having to expose the app in the settings file? I seem to be able to specify the app via #override_settings, but the migrations are not ran.
Ex:
#override_settings(INSTALLED_APPS=['reusable_app'])
class TestReusableApp(TestCase):
def test_something(self):
...
If reusable_app is not specified in the settings module INSTALLED_APPS this still yields a ProgrammingError. Am I missing something or is there another approach?
I think the issue here is that the test runner is setting up the tables before you add the app with #override_settings.
Normally what I do with reusable apps is to run the tests in the context of an "example" app, with settings that include the app your want to test. Usually works pretty well, as I'm packaging the reusable app separately. Here's an example of this from a past project of mine.
However, if that's not possible, you might try to override setUp in your tests, and call the "migrate" command within that code. For example:
from django.core.management import call_command
#override_settings(INSTALLED_APPS=['reusable_app'])
MyTestCase(TestCase):
def setUp(self):
call_command('migrate', 'reusable_app')
This is a bit messy, but it might be worth trying. Depending on how things go, you might also have to run django.setup().

What's the best way to make a new migration in a standalone Django app?

I have a Django app which was spun out a while ago from the project it was originally built for, made into a separate standalone app, and put on PyPI (https://pypi.python.org/pypi/mysociety-django-images). The app is built expecting to be run with Django 1.7+.
I'd now like to make a change to one of the models there - just changing a max_length on a field. I can't see anything in the documentation about how to make a new migration for it? Do I need to make an example project and use that, or is there a better way?
You can do this by making a script like:
#!/path/to/your python
import sys
import django
from django.conf import settings
from django.core.management import call_command
settings.configure(
DEBUG=True,
INSTALLED_APPS=(
'django.contrib.contenttypes',
'yourAppName',
),
)
django.setup()
call_command('makemigrations', 'yourAppName')
(this is also how we go about testing our standalone apps).
I don't know which is the better practice between this and create an example project (this appears lighter to do).

django - how to disable apps

I have multiple settings_x.py
I want to disable app1 which is inside INSTALLED_APPS of one settings_1.py
I tried to comment the app, but the app is still avalaible from urls.py.
how can I do this? I dont want to delete, I just want to turn off the app.
in urls.py of project ,import settings of project.
from django.conf import settings
in urls.py of project, add this code.
if 'app1' in settings.INSTALLED_APPS:
urlpatterns += url(r'^app1/', include('app1.urls'), name='app1'),
if you add this code, system will check if the app is added to INSTALLED_APPS list in settings.py or not. If it does not exist, system will not add its urls.py configurations and also the urls of app will not work.
Apps are available even though they are not specified in settings.py. I can't imagine your case when you want to make the app unavailable from urls.py.
A solution to your problem can be using a version control system like git and using multiple branches. Delete the app in the branch where you don't need the app.

Heroku application structure for Django

I started a Django 1.6 application locally, with the structure that it came with:
project
django_folder
wsgi.py
my_app
views.py
models.py
...
my_second_app
views.py
models.py
...
Now when I try and deploy on Heroku, it only seems to work with the Procfile in the top directory. I seem to be able to move manage.py around without problems.
My problem is that I have environmental variables set so that in my_app views.py I do the following:
from models import my_model
When I put it on Heroku, it seems that I need to specify my_app
from my_app.models import my_model
Is it possible to set an environmental variable in Heroku so I don't need the myapp in front of models? (My second app is not finished, but partly integrated. It is going to be a pain to change all the imports in both apps). When I add my_app in settings.py is this supposed to affect import paths?
You don't need environment variables, just use relative imports. So in your views.py:
from .models import MyModel
Note the leading dot making this a relative import. In this case there's no need to do anything more. This is the standard pythonic way of doing things.

Best practices to integrate a django app with other django apps

In Django:
a) What is the best way to test that another app is installed? (By installed I mean to be in INSTALLED_APPS)
b) What is the recommended way to alter the behaviour of the current app accordingly. I understand that:
if "app_to_test" in settings.INSTALLED_APPS:
# Do something given app_to_test is installed
else:
# Do something given app_to_test is NOT installed
is possible, but is there another way? is this the recommended way?
c) What is the recommended practice to import modules that are only required if another app is installed? import then inside of the if block that test for the installed app?
I tend to favour checking INSTALLED_APPS as you have listed in your question.
if DEBUG and 'debug_toolbar' not in INSTALLED_APPS:
INSTALLED_APPS.append('debug_toolbar')
INTERNAL_IPS = ('127.0.0.1',)
This works well when you have settings distributed across different settings files that don't necessarily have knowledge of the other. eg I might have a shared_settings.py which contains a base set of INSTALLED_APPS, then a debug_settings.py which imports shared_settings.py and then adds any additional apps as required.
The same applies for non-settings. For example, if you have Django South installed and want to create introspection rules for South only if it's installed, I would do this:
if 'south' in settings.INSTALLED_APPS:
from south.modelsinspector import add_introspection_rules
# Let South introspect custom fields for migration rules.
add_introspection_rules([], [r"^myapp\.models\.fields\.SomeCustomField"])
As I see it, there's no need to try and import a module if you know there's the possibility that it may not be installed. If the user has listed the module in INSTALLED_APPS then it is expected to be importable.
That?
try:
# Test it
from an_app import something
except ImportError as e:
from another_app import something
#Do something else