I have gone through a few tutorials on creating a web application in Django. Based on the different tutorials so far, everyone seems to have a slightly different ways of storing their static files and templates.
In one particular tutorial, the author created a static folder at the same level as the project folder. Within the static folder, he created four more folders.They are :
media
static
static-only
templates
Within static, he created:
css
js
within templates, he stores all the web app templates such as base.html, aboutus.html, etc.
However, in the official django documentation, it says
https://docs.djangoproject.com/en/dev/howto/static-files/#serving-static-files-during-development
Store your static files in a folder called static in your app. For example my_app/static/my_app/myimage.jpg.
May I ask which is the most common way of doing it? Many thanks!
It depends. Since my apps share the same set of static and templates I store them in root dirs:
# Settings
STATIC_URL = '/static/'
STATIC_ROOT = abspath('static')
STATICFILES_DIRS = (abspath('styles'),)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
...
)
TEMPLATE_DIRS = (abspath('templates'),)
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
# All styles are in one place
├── styles
│ ├── less
│ ├── js
# App's templates are stored in privite dirs so I can move them in app dir any time
# without changing my code: flatpages/flatpage_detail.html Also it works well with
# class based views.
├── templates
│ ├── base.html
│ ├── flaptages/
│ │ └── flatpage_detail.html
│ ├── another_app/
│ │ └── another_app_detail.html
Then I do manage.py collecstatic and have all static in root/static dir.
It fits me. But if I would make an app to share with community I will put static and templates in it's own dir as described in docs.
Related
example app tree:
articles
├── admin.py
├── apps.py
├── models.py
├── static
│ ├── css
│ │ ├── article_change.css
│ │ ├── article_create.css
│ │ ├── article_detail.css
│ └── js (obfuscated)
│ ├── article_create.js
│ ├── article_list.js
│ ├── edit_process.js
│ ├── editor.js
│ └── js (readable)
│ ├── article_create.js
│ ├── article_list.js
│ ├── edit_process.js
│ └── editor.js
├── templates
│ └── articles
│ ├── article_create.html
│ ├── article_detail.html
│ ├── edit_process.html
│ └── editor.html
├── tests.py
├── urls.py
└── views.py
static/js/js contains javascript that is human readable
static/js contains obfuscated javascript files.
I wrote a template tag to includes files:
#register.simple_tag
def jstatic(path):
s = ''
if settings.DEBUG:
s = 'js/'
return static(s + path)
in templates, I can do:
<script src="{% jstatic 'js/info.js' %}"></script>
which conditionally renders static javascript files based on DEBUG mode. whereas, if not in DEBUG mode, will serve obfuscated files.
the thing is, I don't want unobfuscated file to be accessed when DEBUG is not on, which is running the application on server.
when debug is on, I want user user only to visit obfuscated files:
static/js/js/info.js
and have no access to
static/js/info.js
all the apps follows this root tree convention, I wonder if there is a way, for me to block static/js/info.js is DEBUG is not on.
I have thought about shell setting directory permissions, but give up eventually. because, it will not work due to the wrapping structure of the directory. and it will be too much work to modify it, in the project there are about 20 apps.
This is not possible through standard configuration. How to solve this depends on your configuration, but there are three ways to solve this:
If you use some kind of minifier/webpack like configuration to obfuscate your JS files, you could move the JS files to a src directory and have your tooling only copy when DEBUG is True, and copy and obfuscate when debug is False.
You can use two static directories, one for readable files, and the other for obfuscated files (something like src/static/* and dist/static/*), and then only point to the source directory on development environments:
STATICFILES_DIRS = [ "src/static", "dist/static"] vs. STATICFILES_DIRS = [ "dist/static"] on production.
In this case, Django's static files finder will return the first match found.
Leave your configuration as is, but use a webserver like NGINX for serving static files (Which is already the recommended way to serve static files.) In NGINX's configuration you can define a location that 404's as long as it appears before the location serving your static files.
i have a django project and my web static files are at 'web/' directory
here is the structure:
➜ web git:(ycw.alpha) tree -L 4
.
└── forward
├── asserts
│ ├── img
│ │ ├── background
│ │ ├── qr
│ │ └── thumb
│ └── style
│ ├── css
│ └── sass
├── index.html
├── package.json
├── script.js
├── source
└── unit
i have configured Nginx conf and i want nginx to directly indicate to 'web/forward/index.html' when i request my own website 'http://example.com'
i do the thing above like this:
location / {
index index.html
root /path/to/my/django/project/;
}
location /index.html {
alias /path/to/my/django/project/web/forward/index.html;
}
it indeed directly redirects to 'index.html', but the question is there are some references in 'index.html' to some static files such as img or css and the paths are relative paths like './asserts/style/css/index.css' so consequently these files are not found as 404
how can i configure it correctly?
The problem has been solved by changing 'root' in location / to '/path/to/the/index/directory' rather than the root directory of the django project, in this way you can still use relative paths of static resources in html file generally.
I'm in the process of refactoring a rather basic/traditional Django webapp to a more modern React-plus-Django-REST setup. I'm far more familiar with Django than React, so where to put the React part is what's confusing to me.
My question is: what are the best practices for folder structure in using both Django and React? Ideas I've had:
Put all React files in their own folder like this:
.
├── app1
│ └── example-files.py
├── app2
│ └── example-files.py
├── manage.py
├── react-django-project
│ ├── settings.py
│ └── urls.py
├── requirements.txt
├── some-app-1
│ └── example-files.py
├── some-app-2
│ └── example-files.py
├── src
│ └── components
│ ├── component1.js
│ └── component2.js
└── ...
Put all React files in the static folder, but this doesn't seem right to me.
Is there an established set of best practices for this?
Most of the time there are two separate projects for the back and the front end:
To build a ReST API using Django I'd strongly recommend you to check out Django REST framework if you haven't already. There is a simple tutorial on that home page that should get you up and running.
For the React app "React Create App" seems to be the standard way to start a project nowadays. See the linked GitHub page for step-by-step instructions.
Then follow this "Proxying API Requests in Development" guide to proxy requests to your API for your development setup.
I agree with Igonato about having separate projects for frontend and backend. As client(Frontend) would make Ajax(API) calls to the server(Backend) and with the response data, client renders the page.
Especially with react, you need to convert the react code to minified js and css for higher performance on the production server.
You may use djangorestframework in the backend and setup a django server. For frontend, here are a couple of options:
1. you can use dva (if you intend to use redux). dva is good. I would recommend not to use redux until the state management in your application gets complicated.
2. If you are not gonna use redux, then you can use create-react-app
For front-end I would recommend to use antd if you want to go for material design based application. It's quite a lot of UI elements that you would need in your application. It's battle tested. I have used it in ~9 applications, I have made in the past 6 months.
As the others mentioned, using different repositories is the common approach to solve this. However for a smaller team / smaller project a single repository should suffice.
To keep everything in one repo you create a separate for folder for the react app, usually I name it projectname-client. If you are using create-react-app you could serve the index.html from the build folder by adding that path to settings file.
# settings.py
# Path to the frontend app build directory
BUILD_DIR = os.path.join(BASE_DIR, '{{ project_name }}-client/build')
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BUILD_DIR
],
...
},
]
STATICFILES_DIRS = [
os.path.join(BUILD_DIR, 'static'),
]
# urls.py
urlpatterns = [
...
path('', TemplateView.as_view(template_name='index.html'), name='index'),
]
If you are interested, I'm working on a django-admin startproject template that sets up the project to work with create-react-app. You can take a look here.
I've covered some related topic here on stackoverflow and on some another websites, but still I can't decide, how should I organize Django apps?
Before, I used CodeIgniter and I liked it organization structure.
Ok.
The basic structure looks like
testsite/
├── manage.py
│
├── testsite/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
└── testapp/
├── __init__.py
├── models.py
├── tests.py
└── views.py
For example, I need model for users and a blog. Do I need write both of it in -testapp/models.py, or it would be better to create different app for blog / users?
You can put it wherever you think it makes the most sense. If you are ONLY going to have one Blog model and no functionality related it it, it could make sense to put it inside of your testapp, but I'm guessing it will have templates associated with it, url paths, views, so I think it should be its own app blog.
The same goes for the user model.
Also make sure you check out djangos built in User model
I'm having a really hard time getting my head around the use of django-compressor.
Here's what I'm attempting to accomplish:
Separation of Static Files & Assets (LESS, Coffeescript)
I would like to separate my LESS CSS and Coffeescript files into an assets directory
e.g.
app
└── assets
├── coffee
│ └── script.coffee
└── less
└── style.less
Leaving static assets such as images in my static directory
e.g.
app
└── static
├── hello.txt
└── photo.jpg
To do this, I've added the assets path to my STATICFILES_DIRS variable to allow django-compressor to find the files (which works as expected). Is this the correct approach? I have been trying to find an independent load path dedicated to django-compressor but didn't have any luck as I don't intend for these assets to be served as statics.
Collection of Files for Production Deployment
For deploying to production, I would then like the compiled CSS & JS files along with other media in my app/static directory (e.g. images and so on) to be collected to an app/static-prod directory. But this doesn't work out so well because the assets are also collected when using the collectstatic command.
e.g.
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ ./manage.py collectstatic --noinput
Copying '/home/fots/django_learning/app/assets/less/style.less'
Copying '/home/fots/django_learning/app/assets/less/import.less'
Copying '/home/fots/django_learning/app/assets/coffee/script.coffee'
Copying '/home/fots/django_learning/app/static/photo.jpg'
Copying '/home/fots/django_learning/app/static/hello.txt'
5 static files copied.
Using the ./manage.py compress command only takes tare of my compiled files, not photo.jpg or hello.txt in this example.
The only possible way I've found to do this is using the --ignore flag with collectstatic
e.g.
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ ./manage.py collectstatic --noinput --ignore=less --ignore=coffee
Copying '/home/fots/django_learning/app/static/photo.jpg'
Copying '/home/fots/django_learning/app/static/hello.txt'
2 static files copied.
I've also messed around with the COMPRESS_ROOT and COMPRESS_URL configuration variables but these only cause further trouble. Changing COMPRESS_ROOT resolves the collectstatic issue but now when using the compress command, the generated files end up in a different location to the static files.
These solutions hardly seem elegant. Is there a better way to do this? I feel like I'm missing something.
Thanks in advance for any help :)
I thought I'd provide the best solution I have found so far but please feel free to suggest better alternatives.
The biggest issue preventing my requirement is the fact that django-compressor uses the same path for its finder and output. The best solution I've found is as follows.
Creating a custom finder
We first create a custom finder based on a new setting I call COMPRESS_SOURCE_ROOT
from compressor.storage import CompressorFileStorage
from compressor.finders import CompressorFinder
from compressor.conf import settings
class CompressorFileAltStorage(CompressorFileStorage):
"""
This alternative django-compressor storage class is utilised
specifically for CompressorAltFinder which allows an independent
find path.
The default for ``location`` is ``COMPRESS_SOURCE_ROOT``.
"""
def __init__(self, location=None, base_url=None, *args, **kwargs):
if location is None:
location = settings.COMPRESS_SOURCE_ROOT
# The base_url is not used by the Finder class so it's irrelevant
base_url = None
super(CompressorFileAltStorage, self).__init__(location, base_url,
*args, **kwargs)
class CompressorAltFinder(CompressorFinder):
"""
A staticfiles finder that looks in COMPRESS_SOURCE_ROOT
for compressed files, to be used during development
with staticfiles development file server or during
deployment.
"""
storage = CompressorFileAltStorage
Using this new finder
Simply add this finder to your STATICFILES_FINDERS setting in addition to the usual 'compressor.finders.CompressorFinder'
e.g.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
'mycomp.CompressorAltFinder',
'compressor.finders.CompressorFinder',
)
And now set up a new setting called COMPRESS_SOURCE_ROOT
e.g.
COMPRESS_SOURCE_ROOT = os.path.join(APP_DIR, 'assets')
I've also set my STATIC_ROOT too
STATIC_ROOT = os.path.join(APP_DIR, 'static-prod')
Testing the Solution in Development
I specifically tested my LESS source code compilation
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ tree app/assets
app/assets
├── coffee
│ └── script.coffee
└── less
├── import.less
└── style.less
With template tags
{% compress css %}
<link rel="stylesheet" type="text/less"
href="{{ STATIC_URL }}less/style.less" />
{% endcompress %}
This is read from the assets directory successfully and updated when I change the files.
The output is placed in the static-prod directory:
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ tree app/static-prod/
app/static-prod/
└── CACHE
├── css
│ ├── style.5abda32cfef7.css
│ └── style.6ca1a3d99280.css
└── js
└── script.8cb4f955df19.js
3 directories, 3 files
Testing the Solution for Production
For your reference, here's what my static directory looks like
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ tree app/static
app/static
├── hello.txt
└── photo.jpg
0 directories, 2 files
So here we go
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ rm -rf app/static-prod
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ ./manage.py collectstatic --noinput
Copying '/home/fots/django_learning/app/static/photo.jpg'
Copying '/home/fots/django_learning/app/static/hello.txt'
2 static files copied.
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ ./manage.py compress
Found 'compress' tags in:
/home/fots/django_learning/app/templates/layout.html
Compressing... done
Compressed 2 block(s) from 1 template(s).
(django-cpython)fots#fotsies-ubprecise-01:~/django_learning$ tree app/static-prod
app/static-prod
├── CACHE
│ ├── css
│ │ └── 5abda32cfef7.css
│ ├── js
│ │ └── 3b9d1c08d2c5.js
│ └── manifest.json
├── hello.txt
└── photo.jpg
3 directories, 5 files
I then ran the webserver as follows and confirmed that the site was operational
./manage.py runserver 0.0.0.0:8000 --insecure
Hope this helps somebody out there :)