Django: how to make STATIC_URL empty? - python

Yep, I want it to work like in Flask framework - there I could set parameters like this:
static_folder=os.getcwd()+"/static/", static_url_path=""
and all the files that lies in ./static/files/blabla.bla would be accessible by mysite.com/files/blabla.bla address. I really don't want to add static after mysite.com.
But if I set STATIC_URL = '/' in Django then I could get my static files by this address, but suddenly I could not fetch my pages that described in urls.py.

I believe this is not supported out of the box. Off the top of my head, one way to do it would be with a special 404 handler that, having failed to match against any of the defined URLs, treats the request as a request for a static resource. This would be reasonably easy to do in the development environment but significantly more difficult when nginx, Apache, and/or gunicorn get involved.
In other words, don't do this. Nest your statics (or put them on a different sub domain) but don't mix the URL hierarchy in this way.

This is really easy to accomplish with Nginx using try_files. Using the pseudo-settings below will make Nginx try to find a static file first, and if it fails then execution is passed to your django app.
server {
...
root /some/path/to/assets/;
try_files $uri #django;
location #django {
...
proxy_pass http://unix:/some/path/to/server.sock;
}
}
Example: The file /some/path/to/assets/myfile.ext will be available as http://mydomain/myfile.ext

Related

Access domain (and port) URL in settings.py file while in localhost development

How do you dynamically access the domain name URL in the settings.py file of Django? (ie "http://localhost:8000")
I am trying to overwrite a package CDN while the internet is unavailable during development, and want to point to the local file in the static files directory. While os.path.join(BASE_DIR, "path/to/local.file") should work, it is context-dependent as to which app/url (ie "http://localhost:8000/app/static/css/bootstrap.min.css
"), and not just the main domain with the static file location appended to the starting server with ./manage.py runserver 0:8000 (ie " http://localhost:8000/static/css/bootstrap.min.css").
Notes:
Because this is in the settings.py, I can't load any apps or reverse because of the error *** django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
I am not in a template, so I can't use the static url
statically defining it won't allow for different port loadings when starting via ./manage.py runserver 0:8000
settings.py is basically a python module, but how can you get the domain within it?
Basically in the settings.py file:
# If in local dev
if "RDS_DB_NAME" not in os.environ:
# the setting for the package I am pointing to a local version
BOOTSTRAP5 = {
"css_url": {
### dynamically get domain here ###
# "href": os.path.join(LOCAL_DIR, "static/css/bootstrap.min.css"),
"href": "static/css/bootstrap.min.css",
}
You can't access the domain in settings.py. When you run ./manage.py runserver 0:8000 you are telling Django to listen on port 8000 of whatever localhost is. But you can't tell from this machine which requests are going to come to this machine. For instance, you could have DNS configured to send www.domain1.com and www.domain2.com to come to this machine which looks like localhost from your perspective. So you can't know "domain" until a requests comes in.
Your machine does however have a local machine name which you could figure out from settings.py. Different OSes do this differently but on Macs you can get it with scutil --get LocalHostName and on other Unixes you can cat /etc/hostname.
Chris Curvey is right that the canonical way to differentiate between environments is with different settings files. Most devs differentiate between local and production environments but you are proposing a third: local with no internet access.
There are 2 steps to making this work.
Detect when to use the "local with no internet" environment.
The du jour way (and easiest way, IMO) to do this is with an environment variable. There are lots of ways to do this. You could, for instance, set LOCAL_NO_INTERNET=True in the environment and then check that variable anytime you need to do something special in your code.
If you really need to detect this automatically you could:
Query for the local machine's name (machine name, not domain, as described above)
Check if the name matches your local dev machine (so that you don't do this thing in prod, etc.)
Check if you don't have internet (ping google.com or something and see if it comes back successfully or times out)
I do not recommend this approach; there are many edge cases. Plus you probably can determine for yourself if you would like to be in "local with no internet" environment and set the environment variable manually.
Serve cached files usually provided by CDN
I think the easiest way, although a little verbose, is to put an if statement in your templates to either target the CDN or your local version (note that you will have to pass LOCAL_NO_INTERNET in the context of the view):
{% if LOCAL_NO_INTERNET %}
<script src="{% static "cdncache/bootstrap.min.js" %}"></script>
{% else %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.min.js" integrity="..." crossorigin="anonymous"></script>
{% endif %}
Or you could do something way more complicated here like a middleware to somehow replace references to CDNs.
I would suggest that instead of defining this new "local with no internet" environment you could change your local setup to always assume "local with no internet". The CDN should speed up requests in production but doesn't do you much good in local development compared with always using your own version of those files.
I've never found a way to find out details about the Django listener.
The canonical way to have different settings in different environments is to have different settings files, and then set the DJANGO_SETTINGS_MODULE environment variable to control which one is used.

Webapp with root location other than /

I'm using Pyramid, pserve (ran via Supervisord) and nginx. If I want my app to be available under location other than / (eg. /xml/) should I add prefix to routes in the app, or is there a way to set everything in nginx? Here's how I do it right now:
nginx:
location /xml {
proxy_pass http://127.0.0.1:6544;
}
Pyramid:
config.add_static_view('/xml/static', 'static', cache_max_age=3600)
config.add_route('system_admin', '/xml/admin')
It's probably best not to do this in nginx alone, because your webapp probably generates URLs of its own, and some of these might contain absolute paths. So if it thinks it's hosted at /, it will generate the wrong URLs, and nginx has no way to know.
If you really want to do it this way, you might try a rewrite rule like this:
location /xml {
rewrite /xml(.*) $1 break;
proxy_pass http://127.0.0.1:6544;
}

Best practice for serving static files

I am developing on a python webserver (Tornado). I plan to place this in a production instance with nginx in front. This will be my first time placing something into a production environment on my own. My question is how to setup files/directories for static serving. For instance my application, allows users to upload photos to the web. I recieve the requests in Tornado, and save to disk. However when a user visits their items page, I would rather the images be pulled from a static server. My question is what is the best practice for getting the images from my dynamic server to the static server? Do I rsync the image directory to the static server, then run a cron that delete the images from the dynamic server?
Best practice is use shared storage, but if can't use it, than you can use "proxy_store" option from nginx. Example from nginx doc:
location /images/ {
root /data/www;
error_page 404 = #fetch;
}
location #fetch {
internal;
proxy_pass http://backend;
proxy_store on;
proxy_store_access user:rw group:rw all:r;
proxy_temp_path /data/temp;
root /data/www;
}

Django can't find my non-python files!

I can't, for the life of me, get Django to find my JavaScript files! I am trying to plug in a custom widget to the admin page, like so:
class MarkItUpWidget(forms.Textarea):
class Media:
js = (
'js/jquery.js',
'js/markitup/jquery.markitup.js',
'js/markitup/sets/markdown/set.js',
'js/markitup.init.js',
)
css = {
'screen': (
'js/markitup/skins/simple/style.css',
'js/markitup/sets/markdown/style.css',
)
}
However, when this code is inserted on my admin page, all of the links are broken, I can't get to any of my JavaScript files. My settings file looks like this: http://pastebin.com/qFVqUXyG
Is there something I am doing wrong? I'm somewhat new to Django.
I guess you're using django-admin runserver to test your website. In that case, have a look at "How to serve static files" (but don't ignore the big fat disclaimer).
Once you're ready to deploy, this chapter contains all the information (provided you go the standard route of Apache/mod_wsgi)
I don't know what the "django way" to include js files is, but I just use a simple regular include in the template, its great since you can dynamically generate the location / filename for these.. oh and if you are using django's test server I don't know how to get it to recognize these or if it even can but all you need is to run an apache server on your local machine and then put the files in the localhost directory and you can include them through localhost by including their full path in the template (i.e., http://localhost/myfiledirectory/myfile.js), also something I do is use amazon s3 to host files since you then get a url for them on there (not that you asked about this but its a quick way to host files if you don't have apache running locally)
Basically, my understanding of Django is that it works differently than a PHP framework, for example, as the files for Django don't sit (or don't need to at least) in the web path (i.e. they do not need to be accessible through the host path but can be anywhere on the machine) this is good for providing extra security, etc but it also means, that to give files a url to download them they need to be in the web hosting path, others may know how to make django do this directly but my quick and dirty method of putting them on the localhost path will work if thats all you're after.

Making Django development server faster at serving static media

I'm using the Django manage.py runserver for developing my application (obviously), but it takes 10 seconds to completely load a page because the development server is very, very slow at serving static media.
Is there any way to speed it up or some kind of workaround? I'm using Windows 7.
Consider using mod_wsgi instead, and having httpd handle the static media.
Development server is simple unsafe single-threaded application, so you cannot do much.
One trick you could try is to redirect /site_media to second development server, but this is ugly and probably wouldn't help that much. So you could try bundling/compressing multiple assets into one css/js (e.g. using YUI Compressor).
And in any case, you should have separate static media server, that can serve multiple assets at once.
Install Firefox (if you haven't already), and install the Firebug Add-On. Restart your browser. In the lower-right corner click the "bug" icon and make sure that in the "Network" tab (it's a dropdown) of the Firebug panel that opens at the bottom of the browser, the network monitor is active.
Now with the network tab of Firebug open, open your Django-generated page that you observed to load slowly. Take a look at the timeline bars. You'll notice that the colored fragment(s) of each bar indicate(s) the reason for each request's total "load" time. Violet, for instance, means that actually the browser is waiting for the server to generate the response. Gray means it's receiving content. And so on. Hovering over the bars will display a color legend.
With Firebug's network monitor you should be able to pinpoint how exactly your browser and/or server are spending their 10 seconds.
Run lighttpd to serve the static content and use the MEDIA_URL to point the pages at the lighttpd server that servers the static stuff.
You can try using django-extensions runserver_plus command with the --threaded option as a replacement for Django's runserver command. Under the hood, it uses Werkzeug as the threaded WSGI server. You may notice a huge improvement in loading times for static files.
Lightning fast ans easy on resources when using NGINX for serving static and media files. Here's how it goes. However, you'll need to adapt some paths according to your use case and system. But I think this will get you started:
1) Download NGINX for your system, in your case Windows:
http://nginx.org/
2) Unpack the zip file. Here's how your NGINX config file may look like. This file lives inside nginx/conf/:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# root path to your project
# use "..." if spaces are in the path
# you may add a drive letter if required, e.g. root c:/foo
# use / instead of \. It's simpler and works
root /example/path/django/project/;
server {
# any free port number will do; Django dev server usually runs on port 80
listen 8000 default;
server_name localhost; # or 127.0.0.1
}
}
3) Start NGINX by calling the nginx.exe - no options needed.
4) Tweak your Djnago project's settings.py file:
if DEBUG:
STATIC_URL = 'http://localhost:8000/static/'
# against Django recommendation, I often still use the static
# directory for user uploads; old-style Django ;-)
MEDIA_URL = 'http://localhost:8000/static/uploads/'
Now, the static URLs in Django should look something like this:
http://localhost:8000/static/js/base.js
... 5) Stop the server by calling:
taskkill /f /IM nginx.exe
Well, that's it. I typed this quickly, so just let me know if anything's unclear or not working for you. I may improve this answer accordingly.

Categories

Resources