I have 3 folders in a Django web application. The folders are as follows: the folder that contains settings.py(project), the folder that contains models.py(application), and a folder that contains a front end react application created by create-react-app.
I would like to build the react front end, copy the build artifacts into a static folder and then run the django application on heroku, but they have made this process practically impossible with my current folder structure. The alternative is to flatten the react application out and have build, src, node_modules, packagejson etc etc etc all at the root of the project, but this seems really bad.
Some config in settings.py:
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, 'static'),
os.path.join(BASE_DIR, 'front-end/build/static')
)
What I run locally inside front-end:
npm run build
What I'm returning from views:
def index(request):
return HttpResponse(loader.get_template('build/index.html').render())
#above line returns index.html that is generated by npm run build
How do I deploy the project described above to Heroku so it can find all static resources?
You can use a symlink link that puts your react's build output into your django directory
For example if your directory structure is like this:
~/project_root/
~/project_root/django/static/
~/project_root/my_react_app/build
cd to ~/project_root/django/static/ and run
ln -s ../../my_react_app/build .
This will create ~/project_root/django/static/build that points to ~/project_root/my_react_app/build
Related
I'm deploying a Django project on Centos 7 server using gitlab runner.
Each time I commit and push the project, gitlab runner tries to remove folders (such as the media folder) that are not in the gitlab repository(are on .gitignore).
I don't want gitlab runner to delete media files.
How can I ignore deleting some files and folders when gitlab runner starts its job?
Thanks in advance.
I found the answer.
I've put the media folder inside the project in the root static/media,
so every time gitlab runner deletes all the files and folders that are not in the project directory in the gitlab (also the media folder).
Simply, I put that media folder outside of the project.
former MEDIA_ROOT in settings.py:
MEDIA_ROOT= os.path.join(BASE_DIR, 'static/media/')
changed it to:
MEDIA_ROOT = '/home/gitlab-runner/builds/path-to-some-folder-outside-of-the-project-root/media/'
former nginx configuration:
location /media/ {
alias /home/gitlab-runner/builds/path-to-my-project/static/media/ ;
}
changed to:
location /media/ {
alias /home/gitlab-runner/builds/path-to-some-folder-outside-of-the-project-root/media/ ;
}
Hope it helps anybody that has this problem.
I am writing a reusable Django app and having problems creating migrations.
I have looked at this question, and I'm still confused. I have the following sort of directory structure:
django-mycleverapp/
django-mycleverapp/django_mycleverapp/
django-mycleverapp/django_mycleverapp/__init__.py
django-mycleverapp/django_mycleverapp/apps.py
django-mycleverapp/django_mycleverapp/models.py
django-mycleverapp/django_mycleverapp/urls.py
django-mycleverapp/django_mycleverapp/views.py
django-mycleverapp/example/
django-mycleverapp/example/manage.py
django-mycleverapp/example/example/
django-mycleverapp/example/example/__init__.py
django-mycleverapp/example/example/settings.py
django-mycleverapp/example/example/urls.py
django-mycleverapp/setup.py
As you can see, the directory "django_mycleverapp" contains my reusable app and the directory "example" contains a test project.
I include the models of "django_mycleverapp" in the INSTALLED_APPS section of the settings for "example".
However, running python ~/example/manage.py makemigrations django_mycleverapp doesn't build any migrations.
Any suggestions?
How am I meant to have a test project that will build migrations in "/django-mycleverapp/django_mycleverapp/migrations"?
Your app should be in the directory of your project. Your directory hierarchy should look like this.
django-mycleverapp/
django-mycleverapp/example/
django-mycleverapp/example/django_mycleverapp/
django-mycleverapp/example/django_mycleverapp/__init__.py
django-mycleverapp/example/django_mycleverapp/apps.py
django-mycleverapp/example/django_mycleverapp/models.py
django-mycleverapp/example/django_mycleverapp/urls.py
django-mycleverapp/example/django_mycleverapp/views.py
django-mycleverapp/example/manage.py
django-mycleverapp/example/example/
django-mycleverapp/example/example/__init__.py
django-mycleverapp/example/example/settings.py
django-mycleverapp/example/example/urls.py
django-mycleverapp/example/setup.py
If you do not want your app to be part of your "example" project, but rather want it to be separated and used by your project "example", you'll have to install it in your project using pip (this requires to have a setup.py at the root of your app).
For instance if you have published your app on a git repository "https://gitlab.com/myuser/myproject.git", you can add to our requirements.txt:
git+https://gitlab.com/myuser/myproject.git#v1.0#egg=myapp_name
If you don't have your app published on a git repository yet, you can add the absolute path to your app to you requirements.txt:
/path/to/django-mycleverapp/django_mycleverapp/
Don't forget to work in a virtualenv when you use pip.
I use django for the backend, in the frontend I use vue.js, so 99% of my CSS it's handled by vue.js, however I need a simple base.css for some customization in the landingpage and few things like this.
Normally in django I would put the file inside app/static/app/base.css then do collectstatic and get it under static/app/ for production.
I would like to avoid to keep it under an app as it's just a file. I'm trying adding a folder under my main "static" folder. But it seems in development django in not fetching it at all, it fetches directly and only static files from apps.
How can I tell django to fetch it directly from the static main folder as it would do in production?
i.e. I want to add a folder called main in my root (where manage.py is) and use only that to store my static files for both production and development, without passing through the single apps.
You can tell Django to look for static files in other directories by using STATICFILES_DIRS settings.
Just add the following code in your settings.py and it should work:
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
I put static files under a app directory which is related to the static files.
for example,
image.jpg is used for templates under exmapleapp. so I locate image.jpg file in a directory /project/exampleapp/static/image.jpg
In Debug=True settings, Dajngo finds static files automatically by django.contrib.staticfiles. If you put static files projoject directory /project/static/, you can set STATICFILES_DIRS = []in settings.py or add like urlspatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) in urls.py(if you want to serve static files manually)
so far, is nothing problem in development right? but you want to deploy, you need to do collectstatic. I am confused from now.
This is what I thought initially.
step1 : you work and test your code in local with DEBUG = True in setting. you continously save your code in git repo.
step2 : you are ready to deploy your code in server. you clone your repo and set apache server for running django framework properly(Alias static, WSGI Daemon process). you do python manage.py collectstatic to serve static file with apache server.
step3 : you keep work in local to improve your code and apply this improvement into your code in server with test.
I got confused and got questions.
Q1 : if you do collectstatic for deployment, there will be static folder(according to STATIC_ROOT settings) with all static files which is spread around in each app folders.
do you do collectstatic in local and send only the static folder which collects all to server? or do you do collectstatic in server according to Static Alias setting in Apache server?
Q2 : Do you change DEBUG = False and ALLOWED_HOSTS =[server IP] in local and save code in git repo and pull it in server??
well, now I am confused with working during development with github and deploying it to server with github with Django settings.
Tell me if you can't understand my question clearly please.
You are using static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) for serving static files in development mode. But in production, (means DEBUG = False) it will be empty list. (static returns empty list). Then collectstatic, in you can use development or production.Its intention is to copy all static files to STATIC_ROOT.So
Q1: Everyone do collectstatic on production to serve static files through webserver(Apache, Nginx)
Q2: For production and development write different settings file. You can see here for ex How to manage local vs production settings in Django?
I'm using django-compressor to concatenate and compress my CSS and JS files on this site. I'm serving static files from an S3 bucket.
On my local copy of the site, using a different S3 bucket, this all works perfectly. But on the live site, hosted on Heroku, it all works except the relative URLs for images in the CSS files do not get re-written.
eg, this line in the CSS file:
background-image: url("../img/glyphicons-halflings-grey.png");
gets rewritten to:
background-image:url('https://my-dev-bucket-name.s3.amazonaws.com/static/img/glyphicons-halflings-grey.png')
on my development site, but isn't touched on the live site. So the live site ends up looking in pepysdiary.s3.amazonaws.com/static/CACHE/img/ for the images (as it's relative to the new, compressed CSS file).
For now, I've put a directory at that location containing the images, but I can't work out why there's this difference. Both sites have this in their settings:
COMPRESS_CSS_FILTERS = [
# Creates absolute urls from relative ones.
'compressor.filters.css_default.CssAbsoluteFilter',
# CSS minimizer.
'compressor.filters.cssmin.CSSMinFilter'
]
And the CSS files are being minimised just fine... but it's like the other filter isn't being applied on the live site.
I recently ran into this issue on heroku, and running the latest version of django-compressor (1.3) does not solve the problem. I will provide the solution that I am using, as well as an explanation of the problems I ran into along the way.
The solution
I created my own 'CssAbsoluteFilter' that removes the settings.DEBUG check from the 'find' method like this:
# compress_filters.py
from compressor.filters.css_default import CssAbsoluteFilter
from compressor.utils import staticfiles
class CustomCssAbsoluteFilter(CssAbsoluteFilter):
def find(self, basename):
# The line below is the original line. I removed settings.DEBUG.
# if settings.DEBUG and basename and staticfiles.finders:
if basename and staticfiles.finders:
return staticfiles.finders.find(basename)
# settings.py
COMPRESS_CSS_FILTERS = [
# 'compressor.filters.css_default.CssAbsoluteFilter',
'app.compress_filters.CustomCssAbsoluteFilter',
'compressor.filters.cssmin.CSSMinFilter',
]
The absolute urls now always work for me whether DEBUG = True or False.
The Problem
The issue is connected to 'compressor.filters.css_default.CssAbsoluteFilter', your DEBUG setting, and the fact that heroku has a read-only file system and overwrites your app files every time you deploy.
The reason compress works correctly on your development server is because CssAbsoluteFilter will always find your static files when DEBUG = True, even if you never run 'collectstatic'. It looks for them in STATICFILES_DIRS.
When DEBUG = False on your production server, CssAbsoluteFilter assumes that static files have already been collected into your COMPRESS_ROOT and won't apply the absolute filter if it can't find the files.
Jerdez, django-compressor's author, explains it like this:
the CssAbsoluteFilter works with DEBUG = False if you've successfully provided the files to work with. During development compressors uses the staticfiles finder as a convenience so you don't have to run collectstatic all the time.
Now for heroku. Even though you are storing your static files on S3, you need to also store them on heroku (using CachedS3BotoStorage). Since heroku is a read-only file system, the only way to do this is to let heroku collect your static files automatically during deployment (see https://devcenter.heroku.com/articles/django-assets).
In my experience, running 'heroku run python manage.py collectstatic --noinput' manually or even in your Procfile will upload the files to S3, but it will NOT save the files to your STATIC_ROOT directory (which compressor uses by default as the COMPRESS_ROOT). You can confirm that your static files have been collected on heroku using 'heroku run ls path/to/collected'.
If your files have been collected on heroku successfully, you should be able to compress your files successfully as well, without the solution I provided above.
However, it seems heroku will only collect static files if you have made changes to your static files since your last deploy. If no changes have been made to your static files, you will see something like "0 of 250 static files copied". This is a problem because heroku completely replaces your app contents when you deploy, so you lose whatever static files were previously collected in COMPRESS_ROOT/STATIC_ROOT. If you try to compress your files after the collected files no longer exist on heroku and DEBUG = False, the CssAbsoluteFilter will not replace the relative urls with absolute urls.
My solution above avoids the heroku problem altogether, and replaces relative css urls with absolute urls even when DEBUG = False.
Hopefully other people will find this information helpful as well.
I've had this exact same problem for a month now, but this is fixed in the 1.3 release (3/18/13, so you were probably on 1.2), so just upgrade:
pip install -U django-compressor
The exact problem I gave up on working out, but it's related to Heroku and CssAbsoluteFilter being called but failing at _converter method. Looking at the 1.3 changelog, the only related commit is this: https://github.com/jezdez/django_compressor/commit/8254f8d707f517ab154ad0d6d77dfc1ac292bf41
I gave up there, life's too short.
Meanwhile this has been fixed in django-compressor 1.6. From the changelog:
Apply CssAbsoluteFilter to precompiled css even when compression is disabled
i.e. the absolute filter is run even with DEBUG = True.