how process static file when deploying django using docker and aws eb - django

I used Django, Docker and AWS Elastic Beanstalk to employ my website. I followed the instruction of https://github.com/glynjackson/django-docker-template.
I met problem when I try to load static file, the browser try to visit mysite.com/static/css/xx.css to get the css and javascipt file which is different with what I run it locally.
In settings.py:
STATIC_URL = '/static/'
STATIC_ROOT = 'static'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
I also used:
# !/bin/sh
cd /var/projects/mysite && python manage.py migrate --noinput && python manage.py collectstatic --noinput
supervisord -n -c /etc/supervisor/supervisord.conf
Currently, I write additional views and urls for javascript and css file. So browser can get these file from url. But how to do it correctly?

Related

Found another file with the destination path 'admin'

I am trying to deploy the app on Heroku but when I run the following command: "python manage.py collectstatic" it returns multiple "Found another file with the destination path 'admin...".
When I "git push heroku" the app, I can see the same error.
Next, the application works, but /admin page doesn't have any format, like it is not reading css, font, etc. I've checked staticfiles/admin and it has its css,font,img and js folder with files.
I've tried all the advices given here, but I'm not finding a solution. Here my settings (see my comments at the end of the code):
import os
import django_heroku
# 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 files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') #Heroku
#STATIC_ROOT = os.path.join(BASE_DIR, 'static') #ok for IBM Cloud
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(STATIC_ROOT, 'media') # if I comment this line and
MEDIA_URL = '/media/' # this line, /admin page has correct css but I don't have images in the application
# Extra places for collectstatic to find static files.(extra heroku)
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
# Next line makes application not work, it shows database errors
django_heroku.settings(locals())
"""
so, I added "release: python manage.py migrate" to procfile, now the app works,
/admin shows format ok, but database seems to be empty, no information is displayed on
site pages, and admin users don't exist anymore (my database is sqlite3).
"""
And what I get when "git push heroku master" is:
remote: Found another file with the destination path 'admin/img/selector-icons.svg'. It will be ignored since only the first encountered file is collected. If this is not what you want, make sure every static file has a unique path.
remote: Found another file with the destination path 'admin/img/calendar-icons.svg'. It will be ignored since only the first encountered file is collected. If this is not what you want, make sure every static file has a unique path.
.
.
.
Please help

Static error when giving the command "python manage.py collectstatic"

When I give the command "python manage.py collectstatic" it gives the following problem
"0 static files copied to '/home/leonard368a/leonard368a.pythonanywhere.com/static', 119 unmodified."
does anyone have any way to solve this?
line of command:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
STATIC_ROOT = "/static/"
Collectstatic command use, when you want to deploy your project on server, command copy all static file on local to server this is main use of this command and it's also be use in local but main perpose is copy all file and put on server file manager,
In your case you use the
STATICFILEES_DIRS and STATIC_ROOT are same so in local file system copy static dir to static that why you need to change STATIC_ROOT='asset' or STATIC_ROOT = os.path.join(BASE_DIR, 'asset') in your root dir
static file configration in python any where
collect static in python any where
If it work let me know

Why python manage.py collectstatic do not copy files to correct location?

The problem I am facing is that my Django project can't find static files.
I was struggling with this issue for quite a while hence,
now I figured where the problem is however, I have no idea how to fix it.
Real static files location:
ls /code/jk/static/jk/css/main.css
ls /code/jk/static/jk/js/main.js
When running: RUN (python /code/jk/manage.py collectstatic --noinput)
I noticed that this provides me a wrong location:
...
61 static files copied to '/code/jk/jk/static', 2 unmodified.
...
There is redundant '/code/jk/jk/static' in the path and I have no idea how to change it.
settings.py
...
STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/'
STATICFILES_DIRS = [STATIC_DIR]
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
MEDIA_DIR = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
MEDIA_ROOT = MEDIA_DIR
...
I am using Django application in docker as following:
Dockerfile
FROM python:3
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
COPY . /code/
RUN (pip install -r reqirements.txt)
RUN (python /code/jk/manage.py migrate)
RUN (python /code/jk/manage.py collectstatic --noinput)
RUN (python /code/jk/manage.py migrate)
# clean packages
RUN apt-get clean
RUN rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*
ENTRYPOINT ["/code/jk/start_gunicorn.sh"]
start_gunicorn.sh
#!/bin/bash
cd /code/jk/
touch ./gunicorn.log
touch ./gunicorn-access.log
tail -n 0 -f ./gunicorn*.log &
#export DJANGO_SETTINGS_MODULE=projectx.settings
exec gunicorn jk.wsgi \
--bind 0.0.0.0:8000 \
--workers 3 \
--log-level=info \
--log-file=./gunicorn.log \
--access-logfile=./gunicorn-access.log \
"$#"
1 - The directory collectstatic collects assets in and directories you store your assets sources in aren't the same.
There are two kinds of directory you must know about with django.
The directories to store your static files sources, from the applications. Usually those are static subdirectories in your applications but you can add your own by setting the STATICFILES_DIRS settings variable.
The directory your static files will be collected into for production and serving. This is defined by STATIC_ROOT and is not the same as the other directories I talked about. In my personnal case, I usually use /path/to/project/staticfiles so I can still use /path/to/project/static to store sources.
Here you seem to mistake both. If I'm not wrong, your /code/jk/static is the directory you expect to get your assets collected into. Yet, you also put some of your sources in it. You shouldn't add assets by hand in this directory, which is collectstatic's job to retrieve them from your sources locations.
[EDIT]: You also should not use a directory as both your STATIC_ROOT location and a location to store your assets sources.
2 - Collectstatic doesn't move your assets to the wrong location, actually it acts exactly as how you defined it.
Assuming that you expect your assets to be collected into /code/jk/static, you should define STATIC_ROOT like this :
# Note: BASE_DIR value should be `/code/jk`
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
And not like this :
PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static')
The later defines PROJECT_ROOT as "The directory containing the current __file__ which should be settings.py". Your settings.py should be contained in /code/jk/jk which is therefore your PROJECT_ROOT value.
So when you define your STATIC_ROOT like a static subdirectory of your PROJECT_ROOT it's perfectly normal to get your assets stored in /code/jk/jk/static.

Why doesn't whitenoise work with django on AWS EB Python deployments?

I am deploying a python app on AWS Elastic Beanstalk, and wrapping the wsgi application with DjangoWhiteNoise wrapper. However, I get 404 on my requests to the static files.
# wsgi.py
...
from whitenoise.django import DjangoWhiteNoise
application = DjangoWhiteNoise(application)
# settings.py
...
STATIC_URL = '/static/'
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
STATIC_ROOT = os.path.abspath(os.path.join(BASE_DIR, '..', '.staticfiles'))
# .ebextensions/01_django.config
option_settings:
"aws:elasticbeanstalk:application:environment":
DJANGO_SETTINGS_MODULE: "myproject.settings.aws_ebs"
PYTHONPATH: "/opt/python/current/app:$PYTHONPATH"
"aws:elasticbeanstalk:container:python":
WSGIPath: "myproject/wsgi.py"
container_commands:
01_migrate:
command: "django-admin.py migrate --noinput"
leader_only: true
02_collectstatic:
command: "django-admin.py collectstatic --noinput"
Is there something I'm missing out here?
This is not easy to catch. However, apache is serving the wsgi application, and if you grep for static in /etc/httpd you will see something suspicius.
[ec2-user#ip-1-1-1-1 ~]$ cd /etc/httpd/
[ec2-user#ip-1-1-1-1 httpd]$ find . -type f -exec grep static {} +
./conf.d/wsgi.conf:Alias /static/ /opt/python/current/app/static/
./conf.d/wsgi.conf:<Directory /opt/python/current/app/static/>
More in depth, inside of the wsgi.conf file:
Alias /static/ /opt/python/current/app/static/
<Directory /opt/python/current/app/static/>
Order allow,deny
Allow from all
</Directory>
This means that requests to /static/some/resource.css will never reach the wsgi application, and the files does not exist in /opt/python/current/app/static/, so it will return 404.
There are a few options to solve this :)
1. Skip WhiteNoise and just serve the files via apache.
Remove the two last lines in wsgi.py, so that you just use the django wsgi application. Also change the below:
# settings.py - set the storage to use djangos built in ManifestStaticFilesStorage
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# .ebextensions/01_django.conf - add this to option_settings section
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": ".staticfiles/"
The drawback with this solution is that the files will not be compressed. However, you will anyways probably use some sort of CDN for your static files, and then the compression of the files will not be any problem. AWS CloudFront is one example of CDN you can use to enable compression of static files.
2. Set STATIC_URL = '/staticfiles/'
Change STATIC_URL to be something else that '/static/', for example '/staticfiles/', this way there will not be any match to the '/static/' alias, and django will serve the static files, not apache.
Side notes
Unfortunally it looks the AWS EB Python environment doesn't allow you to remove the /static/ Alias, neither using eb command line tool, nor using the Web interface. Take a look here:

Install and Deploy Django app on Heroku

I often forget steps and wish there was a quick instructional guide on deploying a django project on Heroku.
How to Install and Deploy a Django app on Heroku?
I have posted a step-by-steps answer for steps that have worked for me.
You will get:
Django app both on heroku and your computer.
Postgres databases on both machines
git/bitbucket
authentication: login, logout, register, forgot pass, email authentication only (optional & default)
static files working on both machines
Bootstrap 3.0.3 included
South Migrations (instructions)
Requirements
heroku account
github/bitbucket account
mac with OSX (tested on 10.9)
UPDATE:
To do an installation the quick way, check out the other answer.
Folder structure
PROJECT_WRAPPER - it will hold everything, including PS
DJANGO_PROJECT - it will hold the code
DJANGO_APP - the main app will have that name
Anywhere you see those, replace with your real names!!!
Virtual Env
If you don’t have virtualenv, you need to get it. It will allow you to have separate installations of software for each project:
pip install virtualenv
then we create our project:
cd ~
mkdir PROJECT_WRAPPER && cd PROJECT_WRAPPER
virtualenv venv
now you have a dedicated folder that will contain independent installations and version of python, django, etc.
We activate and and start working on project the following way:
source venv/bin/activate
Postrges app
Just before we continue, we will install postgres.app. Grab it from:
http://postgresapp.com/
Install.
We will now hook up our environment with it:
PATH=/Applications/Postgres.app/Contents/MacOS/bin/:$PATH
Requirements.txt
Now we will need to install the following things:
Python, Django - no explanations required
South - Migrations of database (dev version of Django does not require it)
django-toolbelt - required by heroku and includes everything required for heroku
psycopg - postgres database
simplejson, mixpanel - these are optional, you could skip if you didn't like
So to create the requirements.txt file, we will get it ready from my git repository:
clone https://raw2.github.com/mgpepe/django-heroku-15/master/requirements.txt -o requirements.txt
Now with one command we will install everything from our requirements.txt:
pip install -r requirements.txt
Great, now we can verify that we have django with:
python -c "import django; print(django.get_version())"
Start a Django Project
Let’s start the project with this line and don’t forget the dot in the end:
django-admin.py startproject DJANGO_PROJECT .
Now if you type ls you should see a folder with your project name that contains your Django project.
To see if it all works run:
python manage.py runserver
DATABASE
Run the Postgres app.
Create a database with (I used my osx username):
createdb YOUR_DATABASE_NAME --owner=YOUR_OSX_USERNAME
change the DATABASES to look like this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'YOUR_DATABASE_NAME',
'USER': 'YOUR_OSX_USERNAME',
'PASSWORD': 'YOUR_DATABASE_PASSWORD', #might be empty string ''
'HOST': '127.0.0.1',
# 'PORT': '5432',
}
}
And also let’s hook up the South migrations. Your INSTALLED_APPS should look like that:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'south',
)
Change the SECRET_KEY variable to something else than what it is.
Now if everything was fine you should be able to create the first tables with:
python manage.py syncdb
FIRST APP
Now make your first app in your project
python manage.py startapp DJANGO_APP
in the file: ~/PROJECT_WRAPPER/DJANGO_PROJECT/settings.py
add the DJANGO_APP app to the list in the variable INSTALLED_APPS. Should look like that:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'south',
'DJANGO_APP',
)
TEMPLATES
in settings file add the line:
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
In order for the templates to be well organized and working, we will copy base.html in one folder and the rest of templates in the app itself:
cd ~/PROJECT_WRAPPER/
mkdir templates
curl https://raw2.github.com/mgpepe/django-heroku-15/master/templates/base.html -o base.html
Now the rest of templates:
cd ~/PROJECT_WRAPPER/DJANGO_APP/
mkdir templates && cd templates
mkdir DJANGO_APP
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/changepass.html -o changepass.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/forgot_pass.html -o forgot_pass.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/home.html -o home.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/login.html -o login.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/logout.html -o logout.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/registration.html -o registration.html
curl https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/templates/DjMainApp/splash.html -o splash.html
AUTH SYSTEM WITH EMAIL
Since it has been lately fashionable to use email instead of username, we will do that too.
*NOTE: if you decide not to use it, you can skip this step BUT you have to edit the views and templates to use username instead of email. *
In settings add the following line:
AUTHENTICATION_BACKENDS = (DJANGO_PROJECT.backends.EmailAuthBackend’,)
then copy the file backends.py in our project directory:
cd ~/PROJECT_WRAPPER/DJANGO_PROJECT/
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/backends.py -o backends.py
HEROKU LOCALLY
You can simulate heroku working on your computer with Foreman. Let’s create the simplest configuration file:
cd ~/PROJECT_WRAPPER
echo "web: gunicorn DJANGO_PROJECT.wsgi" > Procfile
foreman start
Now that you see it working without errors stop it with CTRL+C
in settings all the way at the bottom add:
# HEROKU
###########################
# Parse database configuration from $DATABASE_URL
if os.environ.has_key('DATABASE_URL'):
import dj_database_url
DATABASES['default'] = dj_database_url.config()
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Allow all host headers
ALLOWED_HOSTS = ['*']
In your DJANGO_PROJECT/wsgi.py file and add the following to bottom:
from dj_static import Cling
application = Cling(get_wsgi_application())
STATIC FILES
Ideally you would server static files from Amazon or something like that. But for simple sites you could use Django. Setting it up requires you to append this in settings file:
# HEROKU STATIC ASSETS CONFIGURATION
################################
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = 'staticfiles'
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
and put all static files in a specific folder. First go to your project folder with something like:
cd ~/PROJECT_WRAPPER/DJANGO_PROJECT/
and now you can just copy/paste the rest:
mkdir static && cd static
mkdir css && cd css
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/static/css/bootstrap.min.css -o bootstrap.min.css
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/static/css/styles.css -o styles.css
cd ..
mkdir js && cd js
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjangoHerokuIn15/static/js/bootstrap.min.js -o bootstrap.min.js
cd ..
mkdir img && cd img
In this last folder, you will put all images you need.
URL SETTINGS AND VIEWS
In urls.py copy these lines right before ‘example’:
url(r'^$', "pmfmain.views.splash", name="splash"),
url(r'^login$', "pmfmain.views.login_view", name="login"),
url(r'^signup$', "pmfmain.views.register", name="signup"),
url(r'^forgot$', "pmfmain.views.forgot_pass", name="forgotmypass"),
url(r'^logout$', "pmfmain.views.logout_user", name="logout"),
url(r'^dashboard$', "pmfmain.views.home", name="home”),
then copy views.py from my github repo to your DJANGO_PROJECT folder:
cd ~/PROJECT_WRAPPER/DJANGO_APP/
rm views.py
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/views.py -o views.py
Do a find & replace replacing DjMainApp with your real DJANGO_APP name throughout the whole views.py
clone https://raw2.github.com/mgpepe/django-heroku-15/master/DjMainApp/forms.py -o forms.py
GIT
Some files need not be in git, so let’s set the config for this:
echo -e "venv\n*.pyc\n*.log\n*.pot\nstaticfiles" > .gitignore
and now lets commit:
git init
git add .
git commit -m ‘initial commit of django app’
Create a repository in git, then copy the git url (the one that ends in .git). Then:
git remote add origin THE_URL
git pull origin master
BITBUCKET ALTERNATIVE
If you don’t want to pay for github and you want your repository private, you can use bitbucket.
Login to your account
Create a new repository
Click add existing project
git remote add origin https://USERNAME#bitbucket.org/USERNAME/REPOSITORY_NAME.git
MULTIPLE HEROKU ACCOUNTS & KEYS
Even if you never have to have multiple heroku accounts, it is an easy way to setup and use it even for one account. So on we go:
cd ~
heroku plugins:install git://github.com/ddollar/heroku-accounts.git
the add a heroku account with:
heroku accounts:add personal
Enter your Heroku credentials.
Email:YOUR_HEROKU_EMAIL
Password: YOUR_HEROKU_PASSWORD
It says it in the console, and you have to do it:
Add the following to your ~/.ssh/config
Host heroku.personal
HostName heroku.com
IdentityFile /PATH/TO/PRIVATE/KEY
IdentitiesOnly yes
Go to your project folder with something like:
cd ~/PROJECT_WRAPPER
and then set the new account as:
heroku accounts:set personal
To create a new ssh KEY:
ssh-keygen -t rsa
When asked for name, write the full path and name as shown. then type your password or leave blank
Then add the keys both to your OSX and heroku:
heroku keys:add ~/.ssh/YOUR_KEY_NAME.pub
ssh-add ~/.ssh/YOUR_KEY_NAME
DEPLOYING HEROKU FILES
Now that you have keys in order, you should be able to do
heroku apps
and see that there are no apps. To add your first app:
heroku apps:create YOUR_APP_NAME
And now to upload to the server:
git push heroku master
now go to YOUR_APP_NAME.herokuapp.com to see your site!
DOMAIN SETUP
remains to be explained if anybody wants, let me know
NOTES
In-depth documentation at:
https://docs.djangoproject.com/en/1.6/intro/tutorial01/
https://devcenter.heroku.com/articles/getting-started-with-django
In my other answer, the process is well described, but takes time. So I have made a ready installation that is good to go in less than 15minutes.
https://github.com/mgpepe/django-heroku-15
If you'd prefer the full explanation with the long path see the answer below.
THESE ARE THE ERRORS WHICH I FIND WHILE WORKING ON DJANGO FOR 2 YEARS [ENJOY]
Dyno should be added/seen in heroku->resources and if it is not added in resources of Heroku then it means there is a problem in the
"Procfile"
web: gunicorn [django_project].wsgi --log-file -
"django_project" above is your project name , change it to your project name
Remember to do changes in the settings.py file
DEBUG=True
ALLOWED_HOSTS = ["your-app.herokuapp.com","127.0.0.1"]
add this in settings.py file
#->this should be in the middleware
'whitenoise.middleware.WhiteNoiseMiddleware',
#->this at the bottom
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
[ First do "pip install django-heroku" ]
place this at the top of settings.py file:
import django_heroku
place this at the bottom of "settings.py" file:
django_heroku.settings(locals())
Heroku only works with postgres, remember this
[ go to https://www.elephantsql.com/ ]
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "",
"USER": "",
"PASSWORD": "",
"HOST": "",
"PORT": "5432",
}
}
Make Sure database in the background, if not running, start "postgres" in the services.msc.
[ This is in taskmanager->Services->postgresql->right click->start]
python manage.py migrate
go to "your app" in heroku and go to "settings" and select "Add buildpack" in the settings and select "python"
####################### Important ##############################
==> Create a new Git repository Initialize a git repository in a new or
existing directory
cd my-project/
git init
heroku git:remote -a iris-django-ml
==> Deploy your application
Commit your code to the repository and deploy it to Heroku using Git.
git add .
git commit -am "make it better"
git push heroku master
"run this command in your directory"
heroku login
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
restart again with deleting your git file of your working directory, delete heroku project (settings -> bottom)