How to link static style files to Django app on Apache - django

I'm in the process of setting up an Apache web server on an Ubuntu VM using Django with the intention of configuring it for production. I used this walk-through to get Apache and Django up and running, and since, I've been following along with the official tutorial provided in the Django docs. I've gotten up to Part 6, which discusses managing static files, but I can't seem to get the styling to apply.
Abbreviated Server File Structure:
/etc/
--apache2/
----apache2.conf
....
/build/
--django/ <-- Django installation
--tstdj/ <-- target project
----manage.py
----polls/
------...
------static/
--------polls
----------styles.css
------templates/
----------....
----------index.html
------urls.py
------views.py
----static/
------....
------polls/
--------styles.css
----tstdj/
------....
------settings.py
------urls.py
------wsgi.py
/etc/apache2/apache2.conf:
....
WSGIDaemonProcess www-data processes=2 threads=12 python-path=/build/tstdj
WSGIProcessGroup www-data
WSGIRestrictEmbedded On
WSGILazyInitialization On
WSGIScriptAlias / /build/tstdj/tstdj/wsgi.py
Alias /static/ /build/tstdj/static
<Directory /build/tstdj/tstdj>
Require all granted
</Directory>
<Directory /build/tstdj/static>
Require all granted
</Directory>
<Directory /static>
Require all granted
</Directory>
/build/tstdj/tstdj/settings.py:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
....
STATIC_ROOT = BASE_DIR + '/static/'
STATIC_URL = '/static/'
STATICFILES_DIRS = [
'/build/tstdj/polls/static',
]
#STATIC_DIRS = 'static'
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
/build/tstdj/polls/templates/polls/index.html:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/styles.css' %}">
<p><span>My name Jeff</span></p>
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li>{{ question. question_text }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
/build/tstdj/polls/static/polls/styles.css:
li a {
color: green;
}
Obviously, the desired output in this case is to have green links. The network tab of the inspector shows 403 errors on the styles.css file, as does attempting to go straight to localhost:8080/static/.
I've run python manage.py collectstatic and sudo service apache2 restart Lord knows how many times. I know there are means of getting the styling to work in development, but I've yet to get them functional for production.

My issue was that I attempting to change permissions in /etc/apache2/apache2.conf rather than /etc/apache2/sites-available/000-default.conf.
Apache 403 while serving Django static files

Related

Content not being served from STATIC_ROOT

Its my first project in django,so i dont know a lot of things.firstly, i want to serve static files from django STATIC_ROOT, not STATICFILES_DIRS.
this is my project tree:
src >>
...db.sqlite3
...manage.py
...mainapp (main module)
...__init__.py
...settings.py
...urls.py
...wsgi.py
...myapp (django app)
...Migrations(Folder)
...__init__.py
...admin.py
...apps.py
...models.py
...tests.py
...views.py
...accounts (django app)
...Migrations(Folder)
...__init__.py
...admin.py
...apps.py
...models.py
...tests.py
...views.py
...templates
...myapp
...home.html
...accounts
...
...
...static
...myapp
...css
...bootstrap.css
...home.css
...js
...images
...accounts
...
...
...
...static_cdn (STATIC_ROOT)
...admin
...
...
...
...myapp
...css
...js
...images
...accounts
...css
...js
...images
in settings.py :
INSTALLED_APPS = [
'myapp',
'accounts',
.....,
.....,
.....,
'django.contrib.staticfiles',
]
.......
.......
.......
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
STATIC_ROOT = os.path.join(BASE_DIR,'static_cdn')
in urls.py :
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
.......
from myapp.views import (
.......,
.......,
)
from accounts.views import (
.......,
.......,
)
urlpatterns = [
.......,
.......,
.......,
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL,document_root=settings.STATIC_ROOT)
in home.html in templates :
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8" name="viewport" content="width=device-width, initial-scale=1">
<title>.......</title>
<link rel="stylesheet" type="text/css" href="{% static 'myapp/css/bootstrap.css'%}"/>
<link rel="stylesheet" type="text/css" href="{% static 'myapp/css/home.css'%}"/>
</head>
<body>
.......
.......
.......
</body>
</html>
Then i run the command:
(clashsite) D:\DjangoSite\clashsite\src>python manage.py collectstatic
and following happens:
211 static files copied to 'D:\DjangoSite\clashsite\src\static_cdn'.
Now,the endpoint,what i want is : i dont want to serve my static files from 'static' folder in my tree, but from 'static_cdn' folder.more precise,i dont want to serve static files from STATICFILES_DIRS , but from STATIC_ROOT. But the content are served from only static folder.if i remove the static folder,static files are not served from static_cdn or STATIC_ROOT.How can i do that??
#ruddra has already explained to you.
to serve your static assets static_cdn in production environment you need a web server like apache or nginx but you can use xampp or wampserver to serve your Django app locally (a mimic production environment as you said) and access it like any web app
served with real domain name (e.g: http://hellodjango.local/)
install mod_wsgi for apache (https://pypi.org/project/mod-wsgi/) globally (meaning deactivate first the current virtual environment of your Django app)
you need to make some changes to wsgi.py file to include activate_this.py script.
and then create vhost conf file for your app
<VirtualHost *:80>
ServerName hellodjango.local
# the root project folder
DocumentRoot "C:/myapps/hellodjango"
WSGIScriptAlias / "C:/myapps/hellodjango/src/mainapp/wsgi.py"
<Directory "C:/myapps/hellodjango/src/mainapp">
<Files wsgi.py>
Require all granted
</Files>
</Directory>
Alias /static_cdn "C:/myapps/hellodjango/src/static_cdn"
<Directory "C:/myapps/hellodjango/src/static_cdn">
Require all granted
</Directory>
# Alias /media_cdn "C:/myapps/hellodjango/src/media_cdn"
# <Directory "C:/myapps/hellodjango/src/media_cdn">
# Require all granted
# </Directory>
...
</VirtualHost>
and don't forget to add 127.0.0.1 hellodjango.local in windows hosts file and restart apache server.
NB: you can also configure MEDIA_URL and MEDIA_ROOT (for file uploads) the same as STATIC_URL and STATIC_ROOT.
hope this brings you the missing piece of puzzle.
Usage of STATIC_ROOT is bit different and it is related to production deployment. What you are seeing here is Django serving contents when you are in DEBUG=True mode. It is serving content through staticfiles app.
STATIC_ROOT is the directory where static files are stored when you run collect static. But serving from that directory is not what django will do. If you are in production mode(aka DEBUG=False), Django will not serve any static contents. Then you need to use a reverse proxy server like NGINX or Apache to serve those static files from STATIC_ROOT directory.
More information can be found regarding this on documentation.

Django Uploaded images not displayed in production

I am aware of this question: Django Uploaded images not displayed in development , I have done everything that it is described, but still can't find a solution. I also have used for reference this: GeeksForGeeks and Uploaded Files and Uploaded Handlers - Django documentation, however, none of them solved my problem.
I have deployed a Django App on a Ubuntu server for the first time using Nginx and gunicorn.
Before deployment, I used port 8000 to test if everything runs as it is supposed to and all was fine. Since I allowed 'Nginx Full' my database images are not showing up.
This is my django project structure:
My virtual environment folder and my main project folder are both in the same directory. I have separated them.
# Create your models here.
class Project(models.Model):
project_name = models.CharField(max_length=120)
project_description = models.CharField(max_length=400)
project_link = models.CharField(max_length=500)
project_image = models.ImageField(upload_to='')
def __str__(self):
return self.project_name
I have set up my settings.py to :
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), '..', 'media').replace('\\','/')
My view gets all the project object from a database and passes those to the template. The template renders successfully all other information related to project model except the image field . In my template I do:
<div class="row text-center mx-auto">
{% for project in projects %}
{% if forloop.counter|mod:2 == 0 %}
<div class="col projects pb-3 pt-3 mb-3 ml-2">
{% else %}
<div class="col projects pb-3 pt-3 mb-3 mr-2">
{% endif %}
<img class="card-img-top pt-2 pl-2 pr-2" src="{{ project.project_image.url}}"
alt="Image could not be found :(" style="height:120px; width:166px !important;" /><br>
<div class="card-body">
<h3 class="card-title ">{{ project.project_name }}</h3>
<p class="card-text dates">{{ project.project_description}}</p>
Link
</div>
</div>
{% if forloop.counter|mod:2 == 0 %}
<div class="w-100"></div>
{% endif %}
{% endfor%}
</div>
</div>
Uploading the images works, it sends them in the project's media directory, the problem is that they are not showing up, the alt="" is activated.
My main urls.py:
urlpatterns = [
path('', include('project.urls')),
path('admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
The gunicorn system file:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=myusername
Group=www-data
WorkingDirectory=/home/myusername/myproject
ExecStart=/home/myusername/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/myusername/myproject/myproject.sock myproject.wsgi:application
[Install]
WantedBy=multi-user.target
Nginx setup:
server {
listen 80;
server_name <my IP> ;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/myusername/myproject;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/myusername/myproject/myproject.sock;
}
}
EDIT: When inspecting the image element of the webpage the source of the image it is "/media/imageNmae.png".
Any help would be appreciated!
EDIT: The solution has been found, the Nginx was not serving the media as Daniel suggested. There is some uWSGI documentation which is worth reading to avoid further similar problems Documentation
Your Nginx is not serving the MEDIA_URL i.e. /media/. You need an Nginx configuration section like you have for /static/
server {
listen 80;
server_name <my IP> ;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/myusername/myproject;
}
location /media/ {
root /home/myusername/myproject;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/myusername/myproject/myproject.sock;
}
}
You may need to run this command :
python manage.py collectstatic from the shell of your platform
if you are using heroku here is the command
heroku run python manage.py collectstatic

How to use a remote static file server while developing with django manage.py runserver

Background: I'm using the Django manage.py runserver for local development. I have the contrib.staticfiles in installed apps and I'm using its {% static %} template tag in my templates.
What I try to achieve: For development, I'd like to use an independent server for serving the static files but use the django development server to serve the Django app. So that I could access the page locally on my computer at http://127.0.0.1:8000, but all the static files would be served from another computer or from a different server on the localhost, as defined by the settings.STATIC_URL variable.
The problem: The settings.STATIC_URL variable is somehow overridden when I'm using the development server. So all my static files are served by the local django development server instead of what I defined in settings.STATIC_URL.
Solution: See Daniel's answer below!
settings.py:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
STATIC_URL = os.path.join('127.0.0.1:666', BASE_DIR, 'static/')
example_template.html:
{% load staticfiles %}
{% load bootstrap3 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery=True%}
{% bootstrap_messages %}
{# Load MyApp CSS #}
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,700subset=greek-ext,vietnamese,cyrillic-ext,latin-ext' rel='stylesheet' type='text/css'>
<link href="{% static 'css/my_app.main.css' %}" rel="stylesheet">
page source when using a browser:
<link href="FULL_PATH_TO_BASE_DIR_HERE/static/css/my_app.main.css" rel="stylesheet">
but expected to see:
<link href="127.0.0.1:666/FULL_PATH_TO_BASE_DIR_HERE/static/css/my_app.main.css" rel="stylesheet">
This isn't anything to do with Django or runserver. It's simply because you are using os.path.join() to join a domain and a path; that function doesn't know about URLs, and will assume that since BASE_DIR starts with a leading slash, it should normalize the whole path to start from there and ignore anything previous:
>>> os.path.join('127.0.0.1', '/foo', 'static')
'/foo/static'
The solution is twofold: don't use os.path.join on URLs, but more importantly, don't use BASE_DIR in your STATIC_URL. The filesystem directory your static files live in has nothing whatsoever to do with the URL they are exposed on. Your STATIC_URL should be something like "http://127.0.0.1:666/static/".

Live site not finding image file

I currently have the function of uploading images on my site. All the images are working uploading correctly, but when I try to display them using the image.url attribute in the view, it gives me a 404 not found error.
My believe it might be something with my Apache config or Django settings.py.
In my Apache config under I have:
Alias media/ /var/www/MySite/media/
<Directory /var/www/MySite/media>
Require all granted
</Directory>
In my settings.py:
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')
MEDIA_URL = 'media/'
In my view I am trying to display the image as follows:
{% for photo in photos %}
<div class="col-md-3 photo-wrapper">
<img src="{{ photo.image.url }}"/>
</div>
{% endfor %}
The image then looks for this url:
http://mysite.co.za/media/profile_photos/photo.png
But it doesn't find the image.
I did check that the image gets uploaded and it does to the correct location.
Also my model for clarification:
image = models.ImageField(upload_to='profile_photos')
Note: This is working fine when I work with the site on my localhost.
Edit:
So while I was trying different fixes I messed up some stuff that caused me to change the Debug in the settings.py to True, then I saw the image was actually being shown. I changed the debug to false again and the image was once again not showing. What would cause dubug to influence this?
The apache alias directive should start with a /
Alias /media/ /var/www/MySite/media/

Managing static/images in Django with AppEngine

I am trying to add an image to my simple google app engine code, but it doesn't work if I follow the tutorial. It works if my image is in my app directory, but not when I move it to static.
When I am using it in plain html like:
<img src="../static/myimage.jpg"></img>
or
 
and many other variations, the image just does not show (it shows when it is outside of static dir). When I am doing it as in the tutorial, defining STATIC_URL in my settings file:
STATIC_URL = '/static/'
And adding this lines (or variations like "/my_image.jpg" and so on)
{% load staticfiles %}
<img src="{% static "my-app/myimage.jpg" %}" alt="My image"/>
causes server error (500). I am using django 1.3
Here is the directory structure:
my-app
\static
myimage.jpg
\templates
base.html
# and other html files
\urls.py, settings.py #and other .py files
App.yaml:
-url: /(.*\.(gif|png|jpg))
static_files: static/\1
upload: static/(.*\.(gif|png|jpg))
setting.py:
ROOT_URLCONF = 'urls'
urls.py:
STATIC_URL = '/static/'
What did you set STATIC_ROOT to?
Generally though, using GAE's static file handlers in app.yaml will give you better caching and probably lower cost than serving the images with django's staticfiles.