webpack and django on Heroku: bundling before collectstatic - python

I am building a django+react app on Heroku, using django-npm which automatically installs all modules from package.json to node-modules dir and then copies everything to staticfiles/ during python manage.py collectstatic (which is triggered by Heroku during deploy).
However, for this configuration to work I need to pre-bundle my React app before deployment and put it into my static folder along with all the CSS, fonts, etc. to be picked up by collectstatic later.
But I don't want to pollute my git diffs with new bundle versions. So, is there a way to make webpack create a bundle during deployment?
I know there is a release command on Heroku where I can put my npm run build. But the problem is it only fires AFTER collectstatic, so my bundle will only be created in static/ folder after this folder is scanned, and won't get copied to staticfiles dir.

Update:
Using bin/pre_compile should no longer be necessary as of March 11, 2019. Heroku will now automatically call an app's build script (if defined in package.json) during Heroku's build process. Source: Heroku Changelog.
Original: You can accomplish this with the (undocumented) pre_compile hook exposed by the heroku/python buildpack.
Add an executable shell file named bin/pre_compile at the top level of your app and it will be called automatically as part of the build process.
cd my-django-app
mkdir bin
echo '#!/usr/bin/env bash' >> bin/pre_compile
echo 'npm run build' >> bin/pre_compile
chmod +x bin/pre_compile

Related

Django+Heroku: compilemessages works but not MY translation file.

I find myself in a very weird situation:
I do not have my .mo files committed into my repo. I plan to generate them after I deploy
I installed the gettext buildpack availabe at https://github.com/piotras/heroku-buildpack-gettext.git
So this are the steps I did:
Deploy to heroku.
Run heroku run python manage,py compilemessages
This is being outputted:
processing file django.po in /app/.heroku/python/lib/python3.6/site-packages/django/contrib/redirects/locale/ru/LC_MESSAGES
processing file django.po in /app/.heroku/python/lib/python3.6/site-packages/django/contrib/redirects/locale/cy/LC_MESSAGES
processing file django.po in /app/prometheus/locale/zh_hans/LC_MESSAGES
processing file django.po in /app/.heroku/python/lib/python3.6/site-packages/django/contrib/gis/locale/sk/LC_MESSAGES
List one of files: heroku run ls /app/.heroku/python/lib/python3.6/site-packages/django/contrib/redirects/locale/zh_Hans/LC_MESSAGES RESULTS: django.mo django.po
List our file: heroku run ls /app/prometheus/locale/zh_hans/LC_MESSAGES/
RESULTS: django.po
django.mo is missing.
I ran python manage.py shell to see if I have some variables wrong:
heroku run python manage.py shell
In [1]: from django from django.conf import settings
In [3]: print(settings.BASE_DIR)
/app/prometheus
In [4]: print(settings.LOCALE_PATHS)
('/app/prometheus/locale',)
So i have no idea why my django.mo file is not being generated.
Any guesses?
Since Heroku 20, gettext is automatically added for the default Python build package. This is only during build and not at runtime. Therefore the command should be executed just after build.
Luckily this can be done using the post compile file in bin/post_compile (no extension like procfile) with the following line:
python manage.py compilemessages
Optionally you can add the specific language (e.g. python manage.py compilemessages -l nl)
Since Heroku automatically adds gettext, there is no more need to add additional build packs (at least for gettext) like the one from Piotras mentioned above.
These files are generated in the build phase and will be part of the compressed image. Therefore they should not be deleted afterwards.
TL;DR: Django.mo is generated and then deleted.
I'm in the same situation and tried to generate the files with
$ heroku run django-admin compilemessages
$ heroku run ls locale/LANG/LC_MESSAGES/
django.po
I didn't want to wait for connecting to Heroku on every command and used
$ heroku run "django-admin compilemessages; ls locale/LANG/LC_MESSAGES/"
django.mo django.po
$ heroku run ls locale/LANG/LC_MESSAGES/
django.po
Turns out, django.mo is created but for some reason it is immediately deleted.
Googling this gives Heroku Help -page Why are my file uploads missing/deleted?:
The Heroku filesystem is ephemeral - that means that any changes to the filesystem whilst the dyno is running only last until that dyno is shut down or restarted. Each dyno boots with a clean copy of the filesystem from the most recent deploy.
What happens is
heroku run COMMAND
starts a new dyno, runs the command in it and shuts down the dyno once the command has exited, so all the files the command created are deleted.
As far as I know, options are either to commit the .mo-files to repo or serve them from storage, for example S3.

Heroku looking for Procfile in wrong directory

I'm trying to work with Django on Heroku and I'm following this tutorial with its Django template https://devcenter.heroku.com/articles/django-app-configuration
https://devcenter.heroku.com/articles/deploying-python
But when i run 'heroku local web' it always look in the wrong directory. I've tried to move the project
(env) D:\Study\Workbench\heroku-testing\testing\env\codeShareApp>heroku local web
[WARN] No ENV file found
[WARN] ENOENT: no such file or directory, open 'C:\Users\William\Procfile'
[FAIL] No Procfile and no package.json file found in Current Directory - See
run_foreman.js --help
The project directory is as follows
env/
codeShareApp/
.idea/
codeShareApp/
.env
manage.py
Procfile
requirements.txt
runtime
include/
Lib/
Scripts/
tcl/
EDIT:
I tried to make a new project with directory like below, but still got the same error
codeShareApp/
codeShareApp/
env/
.env
manage.py
Procfile
requirements.txt
runtime
I encounter this problem also in a project; I solved this by Making sure that the Procfile is using the correct syntax, and that there are no extra tabs or newlines in the file.
especially whitespcae.
I dont know why, but I tried it on another machine and it works just fine. It seems that it has something to do with heroku cli 6.13 because the error only occurs after it updates from version 5.12 to 6.12
The documentation says:
The file must be placed in the root directory of your application. It will not function if placed in a subdirectory.
Try to do this and it should work. See the docs for more information.

Deploying a simple python script to Heroku without Flask or Django

I'm trying to deploy a python script, but I get this error
Failed to detect app matching https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/python.tgz buildpack
What files I have right now:
automation.py
A simple python script which imports praw, time, os and inspect.
requirements.txt
As described in the Heroku documents, I have created this file by running pip freeze > requirements.txt, containing:
astroid==1.5.2
colorama==0.3.8
isort==4.2.5
lazy-object-proxy==1.2.2
mccabe==0.6.1
praw==4.4.1.dev0
prawcore==0.10.1
pylint==1.7.1
requests==2.13.0
six==1.10.0
update-checker==0.16
wrapt==1.10.10
runtime.txt
Again as described in Heroku documents, this file contains the runtime for my script, containing:
python-3.6.0
I have changed my remote to heroku, added all files, commited and pushed to heroku master, but I get the error mentioned in the beginning. Is there something I'm doing wrong? I have seen this answer, but I'm not convinced. Would like to avoid any frameworks if possible.
git ls-files output
.gitignore
LICENSE
README.md
requirements.txt
runtime.txt
automation.py
In addition to runtime.txt and requirements.txt, a Procfile is required - that's how Heroku knows what script to run for your app. Without it, Heroku doesn't know automation.py is anything special. Note though - if your script doesn't listen on any port, define the process name as "worker" or anything other than "web". If you define it as "web" Heroku will expect it to bind to an externally visible port (not on localhost). If Heroku doesn't detect a port bind within 60 seconds, it reports the app as failed to start

Error while deploy my django website on heroku

I created a personal portfolio website using django and it also includes a blog. You can see the exact directory listing and source code in my github repository by clicking here
I have the procfile and the requirements.txt files as said in the heroku website and did the following in command prompt as directed by heroku :
$ heroku login
$ heroku git:clone -a appname
$ cd appname
$ git add .
$ git commit -am "make it better"
$ git push heroku master
Now I see the following error while deploying and the push fails :
Warning: Your application is missing a Procfile. This file tells Heroku how to run your application.
Yes there is a procfile in the directory though.
Please help me deploy this website in heroku.
Your file is called Procfile.txt. It should be called just Procfile.
It might be that you made a .txt file instead of a non-extension one or that you named it procfile and not Procfile. Heroku is sensitive about capitalisation.

How to deploy / migrate an existing django app / project to a production server on Heroku?

I have a basic django app (Newsdiffs)that runs just fine at localhost:8000 with python website/manage.py runserver but I'd like to migrate it to Heroku and I can't figure out what my next step is.
I thought getting it running locally would translate to running it on Heroku, but I'm realizing that python website/manage.py runserver is launching the dev settings and I'm not sure how to tell it to use the main settings.
All that is in my Procfile is this:
web: python website/manage.py runserver
Locally, that works fine, though it launches it at http://127.0.0.1:8000/ which is probably not what I want on Heroku. So how do I figure out where to set the hostname and port? I don't see either in the app anyplace.
I have just drawn this list for myself two days ago.
It was put together after having followed the steps described in Heroku's help pages for python.
It's by no means definitive nor perfect, and it will change, but it's a valid trace, since I was able to put the site online.
Some issues remain, to be checked thoroughly, e.g. the location of the media/ directory where files are uploaded should/could live outside your project for security reasons (now it works, but I have noticed if the dyno sleeps then the files are not reached/displayed by the template later).
The same goes for the staticfiles/ directory (although this one seems to work fine).
Also, you might want to set django's debug mode to false.
So here it is:
My first steps to deploy an EXISTING django application to Heroku
ASSUMPTIONS:
a) your django project is in a virtual environment already
b) you have already collected all your project's required packages with
pip freeze > requirements.txt
and committed it to git
git add requirements.txt
git commit -m 'my prj requirements'
0) Activate your project's virtual environment
workon xyz #using virtualenvwrapper
then go to your django project's directory (DPD for short) if not already taken there
cd ~/prj/xyz (or cdproject with virtualenvwrapper if setup properly)
and create a new git branch for heroku twiddling to prevent messing things up
git checkout -b he
1) Create the app on heroku
heroku create xyz
that also adds heroku as a remote of your repo
2) Add the needed packages to requirements.txt
vi requirements.txt
add
dj-database-url==0.3.0
django-postgrespool==0.3.0
gunicorn==19.3.0
psycopg2==2.6
django-toolbelt==0.0.1
static3==0.5.1
whitenoise==2.0.3
3) Install all dependencies in the local venv
pip install -r requirements.txt --allow-all-external
4) Setup the heroku django settings
cd xyz
create a copy
cp setting.py settings_heroku.py
and edit it
vi settings_heroku.py
import os
import dj_database_url
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'), )
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
replace django's std db cfg with
DATABASES['default'] = dj_database_url.config()
DATABASES['default']['ENGINE'] = 'django_postgrespool'
and
WSGI_APPLICATION = 'xyz.wsgi_heroku.application'
5) Configure the necessary environment variables (heroku configs)
edit the .env file
vi .env
e.g.
DJANGO_SECRET_KEY=whatever
EMAIL_HOST_USER=youruser#gmail.com
EMAIL_HOST_PASSWORD=whateveritis
and/or set them manually if needed (in my case .env had no effect, wasn't loaded apparently, and had to set the vars manually for now)
heroku config:set DJANGO_SECRET_KEY=whatever
heroku config:set EMAIL_HOST_USER=youruser#gmail.com
heroku config:set EMAIL_HOST_PASSWORD=whateveritis
6) Create a separate wsgi file for heroku
cd xyx
cp wsgi.py wsgi_heroku.py
and edit it to make it point to the right settings
vi wsgi_heroku.py
from whitenoise.django import DjangoWhiteNoise
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "xyz.settings_heroku")
application = get_wsgi_application()
application = DjangoWhiteNoise(application)
7) Make sure all the templates use
{% load staticfiles %}
8) Define the Procfile file so that it points to the right wsgi
e.g.
cd ~/prj/xyz (DPD)
vi Procfile
add
web: gunicorn xyz.wsgi_heroku --log-file -
9) Collect all static content into DPD/staticfiles/
locally, make sure django points to the right wsgi settings
export WSGI_APPLICATION=blogger.wsgi_heroku.application
python manage.py collectstatic
10) add the changes to the local git repo (he branch)
git add --all .
git commit -m 'first 4 heroku'
11) check the whole thing works locally
heroku local # in heroku's help they also add `web`, not needed?!
12) push your code to heroku
git push heroku he:master
13) make sure a instance of the app is running
heroku ps:scale web=1
14) create the tables on the heroku DB
heroku run python manage.py migrate
Note: if you see a message that says, “You just installed Django’s auth system, which means you don’t have any superusers defined. Would you like to create one now?”, type no.
15) add the superuser to the heroku DB
heroku run bash
python manage.py createsuperuser
and fill in the details, as usual
16) Populate the DB with the necessary fixtures
heroku run python manage.py loaddata yourfile.json
17) Visit the website page on heroku's webserver
heroku open
or go to
https://xyz.herokuapp.com/
and the admin
https://xyz.herokuapp.com/admin/
and the DB
https://xyz.herokuapp.com/db
Useful commands:
View the app's logs
heroku logs [--tail]
List add-ons deployed
heroku addons
and use one:
heroku addons:open <add-on-name>
Run a command on heroku (the remote env, where you are deploying)
heroku run python manage.py shell
heroku run bash
Set a config var on Heroku
heroku config:set VARNAME=whatever
View the config vars that are set (including the DB's)
heroku config
View postgres DB details
heroku pg
If you know some python and have a lot of experience building web apps in other languages but don't totally understand where Heroku fits, I highly recommend Discover Flask, which patched a lot of the holes in my understanding of how these pieces all fit together.
Some of the things that I worked out:
you really do need an isolated virtual environment if you're going to deploy to Heroku, because Heroku installs Python modules from the requirements.txt file.
Gunicorn is a web server, and you definitely need to run your app under Gunicorn or it won't run on Heroku.
The "Procfile" doesn't just give the command you use to run the app locally. And Heroku requires it. So if you've got an app that was built to run on Heroku and it doesn't include a Procfile, they left something out.
You don't tell Heroku what your hostname is. When you run heroku create it should tell you what your domain name is going to be. And every time you run git push heroku master (or whatever branch you're pushing, maybe it isn't master), Heroku will (try to) restart your app.
Heroku doesn't support sqlite. You have to run your Production DB in Postgres.
This doesn't directly answer my question, but it does fill in some of the missing pieces that were making it hard for me to even ask the right question. RTFM notwithstanding. :)

Categories