Django in a Subdirectory using fcgi - django

I'm trying to avoid having to somehow add a context_processor to add the base url of my project to every url I use in all of my templates.
My django project is nestled under a subdirectory(lets call it foo) and a lot of my urls in my templates are similar to this:
<a href='/somepath'>whatever</a>
This works fine for a project that is hosted on the root of a domain, but in this case since I am under the subdirectory foo the url would actually point to
www.example.com/somepath
The interesting thing is that the Admin site works fine. All of its url's are pointing to
foo/admin/...
I suspect I'm not searching for the correct terms to find the answer to this.
.htaccess
AddHandler fcgid-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ foo.fcgi/$1 [L]
.fcgi
#!/usr/bin/python
import sys, os
# Current Path
cwd = os.path.join( os.path.dirname( os.path.abspath( __file__ ) ) )
# Activate current virtualenv
activate_this = os.path.join( cwd, 'bin', 'activate_this.py' )
execfile( activate_this, dict( __file__ = activate_this ) )
# Add a custom Python path.
sys.path.insert( 0, os.path.join( cwd, 'foo' ) )
os.environ['DJANGO_SETTINGS_MODULE'] = 'foo.settings'
from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")
Most url's I can use the {% url %} and FORCE_SCRIPT_NAME to have work correctly, but for the url's that I do not have an entry in urls.py to reverse() with, I'm not sure if I should just use the FORCE_SCRIPT_NAME variable in the template for them or is there a better way?

Here is how I solved the problem. Not sure if this is the best way to do it, but it will do for now.
Ensure you have FORCE_SCRIPT_NAME set to whatever your sub directory is
Created context_processors.py inside same directory as settings.py
Added context_processors.url_prefix to settings.py under CONTEXT_PROCESSORS
Anywhere in a template that you cannot use the {% url %} tag, just prepend with {{ URL_PREFIX }}
context_processors.py
from django.conf import settings # import the settings file
def url_prefix(request):
# return the value you want as a dictionnary. you may add multiple values in there.
return {'URL_PREFIX': settings.FORCE_SCRIPT_NAME}
settings.py
CONTEXT_PROCESSORS = (
...,
'context_processors.url_prefix',
)

Related

Django - remove www from URLs

I've added this to my .htacces:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]
but then trying to reach www.example.com redirects me to:
http://example.com/example/wsgi.py/
because i have WSGIScriptAlias / home/www/example.com/example/wsgi.py directive in my httpd.conf and of course i get 404 error.
Eventually, i've managed to fix this by adding next line in my urls.py:
url(r'^example/wsgi.py/$', index), (so it redirects to home page)
but i'm not quite sure that this is the right way to do it (because when i try to reach example.com i see that web browser changes address quickly to www.example.com and then again to example.com)
If anyone would ask, yes i've seen this but this didn't help me either, because browser gets url recursive problem (example.com/example.com/example.com/example.com/example.com...)
EDIT : FOLDER STRUCTURE
This is my folder structure:
\mysite\
static\
media\
.htaccess
manage.py
mysite\
templates
templatetags
tinymce
static
urls.py
settigs.py
views.py
wsgi.py
models.py
forms.py
__init__.py
I know this has been answered some time back but to add to the answer given above use
host.startswith('www.')
its more readable and also you should use permanent redirect to give the browser correct response header.
from django import http
class NoWWWRedirectMiddleware(object):
def process_request(self, request):
host = request.get_host()
if host.startswith('www.'):
if request.method == 'GET': # if wanna be a prefect REST citizen, consider HEAD and OPTIONS here as well
no_www_host = host[4:]
url = request.build_absolute_uri().replace(host, no_www_host, 1)
return http.HttpResponsePermanentRedirect(url)
I find it much simpler to accomplish no-www redirects with middleware that with with Apache mod_rewrite config.
The middleware that you linked to looks like it does the trick. I'm guessing your problems came from Apache config - make sure you remove all mod_rewrite commands (Rewrite* stuff) and then restart the apache server (ref. Apache docs but check for your OS, might be specific).
There is only one additional tweak that you should to: make sure you don't redirect any POST requests, because that might result in lost data (tangent ref: Why doesn't HTTP have POST redirect?).
Anyways, this is what I use, worked quite well for me:
from django.http import HttpResponseRedirect
class NoWWWRedirectMiddleware(object):
def process_request(self, request):
if request.method == 'GET': # if wanna be a prefect REST citizen, consider HEAD and OPTIONS here as well
host = request.get_host()
if host.lower().find('www.') == 0:
no_www_host = host[4:]
url = request.build_absolute_uri().replace(host, no_www_host, 1)
return HttpResponseRedirect(url)
To use it, put in a file somewhere, maybe mysite/mysite/middleware.py.
Then make sure it's run, in your settings.py:
MIDDLEWARE_CLASSES = (
'mysite.middleware.NoWWWRedirectMiddleware',
# ... other middleware ...
If there is no MIDDLEWARE_CLASSES in your settings.py then copy the defaults from here in the Django docs but make you're looking at the correct version of Django, there are some changes in 1.7!
Modified version that works with Django 1.11+ style middleware:
from django.http import HttpResponsePermanentRedirect
class NoWWWRedirectMiddleware:
def __init__(self, get_response=None):
self.get_response = get_response
def __call__(self, request):
response = self.process_request(request)
return response or self.get_response(request)
def process_request(self, request):
host = request.get_host()
if host.startswith('www.'):
if request.method == 'GET':
no_www = host[4:]
url = request.build_absolute_uri().replace(host, no_www, 1)
return HttpResponsePermanentRedirect(url)
This Apache configuration works for me:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com$ [NC]
RewriteRule ^(.*)$ http://example.com$1 [R=301,L]
WSGIScriptAlias / /home/www/example.com/example/wsgi.py
WSGIPythonPath /home/www/example.com/example
<Directory /home/www/example.com/example>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

TemplateDoesNotExist Django Error

I am trying to build a login page form. In my urls.py, I have linked the file to the built in Django login view, and pass in the path to a template directory. I have login folder inside the template and login.html file inside the login folder.
(r'^login/$', 'django.contrib.auth.views.login', {
'template_name': 'login/login.html'
}),
In settings.py, I have provided the directory where my templates are being stored.
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__),'templates'),
)
When I run the runserver command, it shows TemplateDoesNotExist
Exception Type: TemplateDoesNotExist
Exception Value:login/login.html
For anyone experiencing the same problem, it turns out the template path was incorrect. I needed to use '../templates', instead of 'templates' in settings.py:
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__),'../templates'),
)
A better approach would be define your Directories in another settings file, to alleviate the need to use ugly relative path in your template dirs:
// _paths.py
SETTINGS_DIR = os.path.dirname(__file__)
// _templates.py
from settings/_paths.py import SETTINGS_DIR
TEMPLATE_DIRS = (
os.path.join(SETTINGS_DIR, 'templates'),
)
Adjust accordingly based on your folder structure.

TemplateDoesNotExist - file exists, no permissions issue

I'm receiving this error when trying to render a template in django:
TemplateDoesNotExist
...
Template-loader postmortem
Django tried loading these templates, in this order:
Using loader django.template.loaders.filesystem.Loader:
Using loader django.template.loaders.app_directories.Loader:
Here's my settings.py entry:
SETTINGS_PATH = os.path.normpath(os.path.dirname(__file__))
TEMPLATE_DIRS = (
os.path.join(SETTINGS_PATH, 'template'),
)
Here's my view that's being called:
def handler(request):
if request.method == 'GET':
NewAppFormSet = modelformset_factory(Application)
return render_to_response(request, "template/apps.html",{"new_app_form":NewAppFormSet})
I've tried every possible combination of paths, adjusting permissions, etc. The real issue seems to be with the template loaders, as they are not recognizing any paths set forth in TEMPLATE_DIRS. I've hardcoded this string, to no avail. I've also ran python manage.py runserver with sudo / as root. I'm at a loss...
I had a very similar issue which was driving me crazy. It turns out that the book I was using to learn Python/Django did not say that I had to set the templates directory in settings.py expressly. Very confusing. I am using Python 2.6 & Django 1.3.1 - maybe a previous version automatically found the templates dir. Anyway, after pulling my hair out for a day and reading a lot on this site I figured out that I had to replace the default TEMPLATE_DIRS assignment with the following in settings.py:
# Find templates in the same folder as settings.py.
SETTINGS_PATH = os.path.realpath(os.path.dirname(__file__))
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
os.path.join(SETTINGS_PATH, 'templates'),
)
Thanks stackoverflow!!
I'm not sure what example I was following that specified the render_to_response shortcut method requires the views' request object to be passed, but it was as easy as changing it to:
return render_to_response("template/apps.html",{"new_app_form":NewAppFormSet()})
Try assigning SETTINGS_PATH with os.path.realpath:
SETTINGS_PATH = os.path.realpath(os.path.dirname(__file__))
By any chance, you might have copy-pasted the TEMPLATE_DIRS you have now, did you leave the default one lower down the SETTINGS file?
From my settings.py:
BASE_DIR = os.path.dirname(__file__)
def RELATIVE_PATH(*args):
return os.path.join(BASE_DIR, *args)
TEMPLATE_DIRS = (
RELATIVE_PATH('template'),
)
what if you try
return render_to_response(request, "apps.html",{"new_app_form":NewAppFormSet})
instead of
return render_to_response(request, "template/apps.html",{"new_app_form":NewAppFormSet})

Why are the Django project URLs not all available to the Django test client?

I've been trying to add the django-lean app to my project.
The django-lean app is not located in the project I'm working on, it is on the PYTHONPATH.
I have not been able to get the django-lean tests to pass.
It seems the issue is that the TestCase defines a value for urls:
urls = 'django_lean.experiments.tests.urls'
As best as I can tell, the tests are only getting the urls located # 'django_lean.experiments.tests.urls', but not
the urls from the rest of the project.
This is causing error messages like:
NoReverseMatch: Reverse for 'index' with arguments '()' and keyword arguments '{}' not found.
These are triggered by {% url %} template tags in the project.
How can I make sure that the all the urls of the project are available for the tests?
EDIT:
Someone showed me a script to print the visible URLs:
import urls
def show_urls(urllist, depth=0):
for entry in urllist:
print " " * depth, entry.regex.pattern
if hasattr(entry, 'url_patterns'):
show_urls(entry.url_patterns, depth + 1)
I called this script from ipdb, this was the output:
ipdb> import urls
ipdb> show_urls(urls.urlpatterns)
^test-experiment/(?P<experiment_name>.*)$
^test-clientsideexperiment/(?P<experiment_name>.*)$
^admin/
^(?P<experiment_name>.+)/$
^$
^main-app/
^goal/(?P<goal_name>.*)$
^confirm_human/$
This corresponds to the urls located # 'django_lean.experiments.tests.urls'
urlpatterns = patterns('django_lean.experiments.tests.views',
url(r'^test-experiment/(?P<experiment_name>.*)$', 'experiment_test'),
url(r'^test-clientsideexperiment/(?P<experiment_name>.*)$', 'clientsideexperiment_test'))
urlpatterns += patterns('',
url(r'^admin/', include('django_lean.experiments.admin_urls')),
url(r'^main-app/', include('django_lean.experiments.urls')),
The issue that I'm having is that my tests all fail because of the named urls from other apps in the project are called by URL template tags are not accessible to the tests.
I'm running Python 2.7 with Django 1.2.1
The solution was pretty simple. Just import the URLs from the main project into the urls.py for the app.
from forum.urls import urlpatterns
or for a more generic solution:
from settings import ROOT_URLCONF as project_urls
urlpatterns = __import__('forum.urls').urls.urlpatterns
To list all the url patterns your django knows you can use the answer suggested here.
Run this from your tests and print/log the output.
Just note that its better to explicitly state where to import the urls from like
from myproject import urls
because you probably have some other modules containing urls files.

How does Django serve media files?

I have set up a Django application that uses images. I think I have set up the media settings MEDIA_ROOT and MEDIA_URL correctly. However the images don't show up. Do you know what can be the problem?
Let consider this example:
The image files are under /home/www/media/app/photos and we are trying to request http://example.com/photos/123.jpg
Should I use these settings?
MEDIA\_ROOT = /home/www/media
MEDIA_URL = http://example.com/app
UPDATE: Forgot to mention that I'm using built-in development server.
FOR DEVELOPMENT ONLY
You can setup a static media server for use with their development server by doing this in your urls.py file. I have attached the code showing how I use it (along with the forced DEBUG conditionals.)
from django.conf import settings
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^$', 'views.index'),
# Accounts
(r'^accounts/login/$', 'views.user_login'),
(r'^accounts/logout/$', 'views.user_logout'),
# Contrib Modules
(r'^admin/(.*)', admin.site.root),
)
if settings.DEBUG :
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
)
I place my MEDIA_ROOT in a subdirectory of html/media and link to it as such in settings.py
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), 'html/media/').replace('\\','/')
After development is finished, the project gets deployed to the web server where static media files are then served by Apache using directives.
Serving static content from Django is discouraged from the developer themselves (if I'm not wrong, it only works when in debug mode). You should use a dedicated web server, instead.
If you really need to do that, anyway, read the documentation on how to serve static files.
This is the correct way of showing image files with ImageField. Imagine we have a user profile picture:
models.py:
UserProfile:
profilePic= models.ImageField( upload_to='PATH_TO_UPLOAD', blank=True, null=True)
settings.py:
MEDIA_ROOT = 'FULL_PATH_OF_MEDIA'
MEDIA_URL = 'URL_OF_MEDIA'
urls.py:
urlpatterns = [
.
.
.
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
PATH_TO_UPLOAD is the path which user upload data goes. This is sub-directory of FULL_PATH_OF_MEDIA, which means the uploaded file will have
FULL_PATH_OF_MEDIA/PATH_TO_UPLOAD
full path.Now this content can be accessed at this url:
SITE_NAME/URL_OF_MEDIA/PATH_TO_UPLOAD
I also recommend reading this on static_files vs media_files
doc
You can just add those lines to your urls.py
from django.urls import re_path
from django.views.static import serve
urlpatterns = [
...
re_path(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}),
]
I suspect you are getting the Django 404 page. Try directly accessing one of your images and see if that's happening.
If so, your need to configure your web server to not send requests within your media hierarchy to Django but to instead serve them directly. Here is a snip from my Apache conf file. The first section tells Apache to send everything to Django. The second section has "SetHandler None" which says "handle stuff under /media in the normal way."
See http://docs.djangoproject.com/en/dev/howto/deployment/modpython/ for all the exciting details.
Partial httpd.conf file for PrinceOfPinot.com (AKA pop):
<Location "/">
SetHandler python-program
PythonAutoReload Off
PythonDebug Off
PythonPath "['/var/www/production/pop', '/usr/local/lib/python2.5/site-packages/django'] + sys.path"
SetEnv DJANGO_SETTINGS_MODULE settings
PythonHandler django.core.handlers.modpython
</Location>
<Location "/media">
SetHandler None
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
</Location>
I'm aware that the original question is with the dev server, but for anyone else who is looking for a production environment answer:
https://docs.djangoproject.com/en/1.8/howto/static-files/deployment/ provides a guide on how to have django serve files in a production environment. From the tone of the guide, it does seem to imply that it is best to have a separate web server to handle the files or use mod_wsgi with Apache