Moving django apps into subfolder and url.py error - django

I have a question about putting django apps into "apps" subdirectory. I have the app called “faktura” in a project_root. I didn’t like the fact it lies there and I want to store all my apps under “apps” subdirectory.
So, I found out that I could extend python path to “apps” subdir, so after looking in the internet, I added this string to settings.py: sys.path.insert(0, os.path.join(PROJECT_PATH, "apps")). Then I added the app to INSTALLED_APPS like “faktura”. Everything worked smooth until I added url(r'^faktura/', include('faktura.urls')) to urls.py in the root. Since that, Django throws the error message “No module named faktura” full taceback is here: http://dpaste.com/737380/
What can be wrong here, why only urls.py can’t find the app? And does it can’t find this app if I added it to the PATH? I spent a morning trying to figure out what’s wrong and now I need your help.

I don't know why the previous answer got -1 aside from maybe a few redundant lines that can be corrected. Anyway, I found a slightly different method that doesn't involve adding anything to the python path.
This is my final directory structure, I will explain in a moment:
mysite
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── apps
│ ├── __init__.py
│ └── myfirstapp
│ ├── __init__.py
│ ├── admin.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
No matter if you have just created your project or if you want to move your apps, create the apps subdirectory that should contain your apps. The trick is to add an __init__.py to that directory.
mkdir apps
touch apps/__init__.py
Now you can move your existing apps into the apps subdirectory. If you would like to create a new one instead here are the commands:
python manage.py mysecondapp
mv mysecondapp apps/
Warning: Don't be tempted to call python manage.py ./apps/mysecondapp. For some reason this deletes all other apps in that directory. I just lost a day of work this way.
Next, you will need to fix a few imports. Your settings.py should be prefixed with apps:
INSTALLED_APPS = (
...
'apps.myfirstapp',
'apps.mysecondapp'
)
Lastly, fix your project's urls.py to prefix apps:
urlpatterns = patterns('',
url(r'^myfirstapp', include('apps.myfirstapp.urls')),
...
)
Depending on how you wrote them, you might also have to fix a few imports inside your app. Either just use from models import MyFirstModel or also prefix it using from apps.myfirstapp.models import MyFirstModel.
In short, if you make your apps directory a python package (by adding __init__.py), you can use it as part of the import path. This should work regardless of the deployment method with no extra configuration.

Use BASE_DIR variable from the settings.py. It should be already defined:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Better not use the __file__ attribute in manage.py and wsgi.py, as they are located in different directories.
So, just add the following to manage.py and wsgi.py (and to the celery.py if you use Celery):
from django.conf import settings
sys.path.append(os.path.join(settings.BASE_DIR, "apps"))
You will end up with the following project structure:
project
├── project
│ ├── __init__.py
│ ├── celery.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── apps
│ ├── app1
│ └── app2
└── manage.py

To keep your Django applications in a subfolder (such as apps/), first add the following to your settings.py:
import os
PROJECT_ROOT = os.path.dirname(__file__)
Then in manage.py:
Right under #!/usr/bin/env python add:
import sys
from os.path import abspath, dirname, join
from site import addsitedir
Right before if __name__ == "__main__" : add:
sys.path.insert(0, join(settings.PROJECT_ROOT, "apps"))

#Radu Gheorghiu's answer; It is not necessary to edit settings.py, and the insert path line can be condensed to 1 line of code.
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "apps"))
I sourced this answer from http://obroll.com/nested-application-inside-apps-sub-folder-in-django-1-3/

Related

How to include urls file from sub sub folder in django

i try to include urls from my Api folder
i tried path('api/', include("main.Apps.Api.apps.urls")) but it doesn't work
in my settings.py i add the app by INSTALLED_APPS += ["main.Apps.Api.apps.ApiConfig"]
and i changed the app name in Api.apps.py to name = 'MikeWebsite.Apps.Api' Everything works
But include the urls return me
ModuleNotFoundError: No module named 'MikeWebsite.Apps.Api.apps.urls'; 'MikeWebsite.Apps.Api.apps' is not a package
my project file tree look like this
main
└───_main
├── __init__.py
├── settings.py
├── urls.py
├── wsgi.py
└──_Apps
├──_Api
| └── urls.py
└── ...
What I'm doing is wrong?
And if you have a good source of information on how to work with apps nested in Django

How to serve `Docs` folder in Django which contains static html files?

I have following code structure in Django.
├── docs
│   └── _build
│      ├── doctrees
│      └── html
│   └── index.html
│  
├── localcoinswap
├── scripts
├── _static
├── _templates
├── tests
└── manage.py
Here the docs folder contains static html files. i.e index.html
Here are some questions regarding to problem:
The docs folder's html should be served as url <domain>/docs/index.html in Django project. How to achieve this
It should be restricted to User's who have is_staff attribute True.
What urlpattern should I use and Which View is useful to serve those static files (Admin restricted)?
Thank you in advance!
Add the base directory for your docs in TEMPLATES setting in settings.py.
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, '_templates'), "add your base directory here"],
...
}
]
In your urls.py, serve the files using TemplateView. To further restrict the url to only the staff users, you can wrap the view in staff_member_required decorator.
from django.contrib.admin.views.decorators import staff_member_required
...
urlpatterns += [url(r'^docs/index\.html$', staff_member_required(TemplateView.as_view(template_name='index.html')), name="index"),]
Make sure the file names for your templates and doc templates don't clash, else the first one evaluated according to the DIR list will always be considered.

Django URL patterns to serve external webpack bundle

I'm writing a django rest framework API (backend) with a react SPA frontend. For the production environment, the front end is served up via nginx at http://example.com/ and the backend is proxied to gunicorn and served from the same domain with a different path - http://example.com/api/
This is all working fine in production, there are no CORS issues as the frontend and backend are both served up under the same domain via nginx.
For local development, I want to be able to replicate a similar setup using ./manage.py runserver and have django serve up the frontend from project/frontend/dist (built by npm build seperately).
Has anyone got any urlpattern wizardry that will allow this to happen and also let the react-router play nicely? I just can't figure it out and it's starting to drive me nuts...
The project structure is something like this if it helps in any explanations.
Project
|
── backend
│   ├── apps
│   ├── config
| | ├── settings.py
| | ├── settings_local.py
| | ├── urls.py
│   ├── manage.py
│   ├── requirements.txt
│   └── venv
├── frontend
│   ├── dist (contains the npm build webpack)
│   ├── node_modules
│   ├── package.json
│   ├── package-lock.json
│   ├── scripts
│   ├── src
│   ├── webpack.config.js
Edit #1
Thanks to another post I was able to get partially the way there by adding this to my urls.py
if settings.DEBUG:
from django.views.generic import RedirectView
from django.contrib.staticfiles.views import serve
bundle_path = os.path.abspath(os.path.join(root_dir, 'frontend', 'dist'))
settings.STATICFILES_DIRS += (bundle_path,)
urlpatterns += [url(r'^$', serve, kwargs={'path': 'index.html'})]
urlpatterns += [url(r'^(?!/?static/)(?!/?media/)(?P<path>.*\..*)$',
RedirectView.as_view(url='/static/%(path)s', permanent=False))]
The only issue I have here is that if I go directly to one of the JS router links, then django tries to interpret it and can't find the route.
What I need now is a catch-all that will redirect to '/' but also keep any extra URL path information on the url
Finally got this to work with all the routing.
Added the webpack dist folder to settings.STATICFILES_DIRS
Added the webpack frontend path to settings.TEMPLATES
Added 3 new urlpatterns to urls.py ( based on a conditional, settings.DEBUG)
urlpatterns += [
url(r'^(?!/?static/)(?!/?media/)(?P<path>.*\..*)$',
RedirectView.as_view(url='/static/%(path)s', permanent=False)),
url(r'^$', TemplateView.as_view(template_name='dist/index.html'), name='frontend'),
url(r'^(?P<path>.*)/$', TemplateView.as_view(template_name='dist/index.html'), name='frontend'),
]
The first redirects any of the asssets for the bundle to be served using django's static files.
The second pattern serves the root path / as a template from the webpack dist folder
The final piece handles all the leftover JS routing paths to go back to the initial root view.
You can use nginx reverse proxy to serve them.
No need config Django's url.
See example here:
http://www.codingpedia.org/ama/how-to-configure-nginx-in-production-to-serve-angular-app-and-reverse-proxy-nodejs

Django tutorial 1 not showing polls

I am taking a test Driven Development course for python (which is awesome) Obeythetestinggoat and so my Django needs work. So I'm taking the Djangoproject.com course and I get all the code entered and the server runs but the polls won't change.
The home page http://127.0.0.1:8000 shows
"It worked!
Congratulations on your first Django-powered page."
Which is great but it won't show the polls or the admin buttons and I've run out of ideas on how to redirect it but not sure the problem.
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
I'm rather proud that I figured out the server and other areas but I just don't know what I am missing to get the page to show the polls.
https://docs.djangoproject.com/en/1.10/intro/tutorial01/
Yes, all you need to do is go to http://127.0.0.1:8000/polls/ . Otherwise if you want put your default polls page on the home page like you intended to do in http://127.0.0.1:8000/
you could do this in your urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^$', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
hope it helps.
http://127.0.0.1:8000 is the main page of your preoject, but in the urls, you define (with regex) how to manage requests to http://127.0.0.1:8000/polls/ and http://127.0.0.1:8000/admin/. You should visit those URLs.
There's a urls.py at the wrong place made by the django-admin startproject mysite command.
.
├── db.sqlite3
├── manage.py
├── mysite
│   ├── asgi.py
│   .
│   .
│   │
│   ├── urls.py <-- right place
│   └── wsgi.py
├── polls
│   .
│   .
│   ├── urls.py
│   └── views.py
└── urls.py <-- wrong place
If you forget to remove it, and keep it, while creating the right one at the right place, it prevents the rules of the right one to be applied.

Use SQLite for Django locally and Postgres on server

I am starting with Django development as a hobby project. So far I have happily worked with SQLite, both in development (i.e. with py manage.py runserver) and in deployment (on Nginx + uWSGI). Now I would also like to learn to use a more robust PostgreSQL database. However, if possible, I would like to skip installing it locally, to avoid installing Postgres on Windows.
I was wondering if it was possible, by means of Django, to use SQLite whenever I use the built-in server and Postgres in deployment, without changing the project code. Couldn't find how to do it.
I can use a workaround and make my deployment procedure change the settings on server each time I deploy. But that's kind of a hack.
You could split your settings.py in multiple settings file e.g.
[projectname]/
├── [projectname]/
│ ├── __init__.py
│ ├── settings/
│ │ │── base.py
│ │ │── development.py
│ │ │── production.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
your base.py includes all code from your current settings.py. specify the different databases in your development.py(sqlite3) and in your production.py (postgresql) and import the base.py in each
from .base import *
Last but not least you'll have to tell django which file it should use. Add
export DJANGO_SETTINGS_MODULE="projectname.settings.development"
to your postactivate of your virtualenv on your development server and
export DJANGO_SETTINGS_MODULE="projectname.settings.production"
on your production server. Don't forget to
unset DJANGO_SETTINGS_MODULE
in your predeactivate.
More infos are here: http://www.marinamele.com/taskbuster-django-tutorial/settings-different-environments-version-control
btw. a great tutorial with a lot of best practices
replace settings.py with
settings/
│── __init__.py
│── base.py
│── development.py
│── production.py
in __init__.py
import os
app_stage = os.environ.get('DJANGO_APP_STAGE', 'dev')
if app_stage == 'prod':
from .production import *
else:
from .development import *
And finally when you launch app for production, make sure you set env DJANGO_APP_STAGE='prod'
Create your database settings in respective files and you are good to go.
Very late reply, but I hope this helps someone in the future.
I found this article on Digital Ocean that has the database option split happening in one settings file. https://docs.digitalocean.com/tutorials/app-deploy-django-app/#configuring-database-access
Makes use of a DEVELOPMENT_MODE system environment variable to split settings. They also included a check to prevent a connection when a command is run like collectstatic.
settings.py file:
import os
import sys
import dj_database_url
DEVELOPMENT_MODE = os.getenv("DEVELOPMENT_MODE", "False") == "True"
if DEVELOPMENT_MODE is True:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
}
}
elif len(sys.argv) > 0 and sys.argv[1] != 'collectstatic':
if os.getenv("DATABASE_URL", None) is None:
raise Exception("DATABASE_URL environment variable not defined")
DATABASES = {
"default": dj_database_url.parse(os.environ.get("DATABASE_URL")),
}
Note: This is also making use of the Django Database URL package, but you could easily adapt for separated database arguments.