Django: reading from STATIC_ROOT during testing - django

I render some pdf from some templates in my project. Well, it seems to work, but...
...I wanna test it!
Problem is that some files I read during rendering are in STATIC_ROOT - so I need to collectstatic when I run tests (kinda wierd!).
Question is: is there a way to work with STATIC_ROOT during testing, but without 'real' collecting static?

I use following way. In you project directory create a file named dev_static_finder.py with these contents.
# -*- coding: utf-8 -*-
from django.core.files.storage import FileSystemStorage
from django.contrib.staticfiles.finders import BaseStorageFinder
from django.conf import settings
class StaticRootFinder(BaseStorageFinder):
storage = FileSystemStorage(settings.STATIC_ROOT, settings.STATIC_URL)
Add this line to your settings.py
STATICFILES_FINDERS += ('dev_static_finder.StaticRootFinder',)
I don't know an easer way.

Related

How to read shapefile in Django view helper function?

As part of my view logic I need to check if Latitude and Longitude points are withing city boundaries.
To do that, I am using city shapefiles with geopandas. It all works ok locally in plain python code.
However, when I run the following code in Django:
LA_geo_df = gpd.read_file('./City_Boundaries/City_Boundaries.shp')
I get the error:
DriverError at /
./City_Boundaries/City_Boundaries.shp: No such file or directory
What is the proper Django way of loading such files?
Auto-generated Django settings file will have a BASE_DIR setting that looks like this
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
This is an absolute file path to the root of your Django app. You can use this setting to build an absolute path to your file
CITY_BOUNDARIES_FILE_PATH = os.path.join(BASE_DIR, 'City_Boundaries', 'City_Boundaries.shp')
Then where you want to load the file you can use the setting
from django.conf import settings
LA_geo_df = gpd.read_file(settings.CITY_BOUNDARIES_FILE_PATH)

Django settings: How to access variables from the settings folder in an app

I have a Django project with the following structure:
--|src
--project
--|settings
--__init__.py
--production.py
--local.py
--|app1
In my app I import the settings (from django.conf import settings) and then as I was following a tutorial they said to do this getattr(settings, VARIABLE). That doesn't work for me. Instead I can do this: settings.VARIABLE. What's the difference?
Oh and I ran type(settings) and it outputted <class 'django.conf.LazySettings'>.
in order to access variables in settings.py file, you can do like this:
for example, I define STATIC_ROOT variable in settings.py file like this:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static', 'static_root')
and I can access to this variable like this:
from django.conf import settings
document_root=settings.STATIC_ROOT
The difference is that for various reasons (see the documentation for details), the settings object is not loaded unless an object is referenced from it.
The LazySettings object is special and you have to access it with settings.SOMETHING.
The reason its called "Lazy" is because the entire object is not loaded and made available to you when you import it. This LazySettings object acts like a proxy to the actual settings object.
project DIR
--|app DIR
--|settings.py <<< your variable API_KEY = '28234-jns-23-23n'
from app.settings import API_KEY

Django model cannot find a static file

in my models.py I have (myfile.txt is 3gb)
with open('/static/myfile.txt', 'rb') as f:
do something..
but it complains
No such file or directory: '/static/myfile.txt'
this is my settings.py
STATIC_ROOT = 'absolute_dir_to_project/app_name/static/'
STATIC_URL = '/static/'
Did I miss any step?
you should prepend the absolute path with SETTINGS's STATIC_URL so that it looks for myfile.txt inside Django:
from django.conf import settings # dont forget to import this guy
with open(settings.STATIC_URL + 'myfile.txt', 'rb') as f:
do something..
The open function is trying to open a file from disk with the path /static/myfile.txt, rather than requesting a file through your Django web app. It doesn't sound like you need to have this file in your static files folder, especially if it's huge and isn't intended for public consumption

Django get the static files URL in view

I'm using reportlab pdfgen to create a PDF. In the PDF there is an image created by drawImage. For this I either need the URL to an image or the path to an image in the view. I managed to build the URL but how would I get the local path to the image?
How I get the URL:
prefix = 'https://' if request.is_secure() else 'http://'
image_url = prefix + request.get_host() + STATIC_URL + "images/logo_80.png"
# Older Django <3.0 (also deprecated in 2.0):
from django.contrib.staticfiles.templatetags.staticfiles import static
# Django 3.0+
from django.templatetags.static import static
url = static('x.jpg')
url now contains '/static/x.jpg', assuming a static path of '/static/'
EDIT: If you're on Django >=3.0, refer to Django get the static files URL in view instead. This was answered with Django 1.X version.
dyve's answer is good one, however, if you're using "cached storage" on your django project and final url paths of the static files should get "hashed"(such as style.aaddd9d8d8d7.css from style.css), then you can't get a precise url with django.templatetags.static.static(). Instead, you must use template tag from django.contrib.staticfiles to get hashed url.
Additionally, in case of using development server, this template tag method returns non-hashed url, so you can use this code regardless of that the host it is development or production! :)
from django.contrib.staticfiles.templatetags.staticfiles import static
# 'css/style.css' file should exist in static path. otherwise, error will occur
url = static('css/style.css')
From Django 3.0 you should use from django.templatetags.static import static:
from django.templatetags.static import static
...
img_url = static('images/logo_80.png')
here's another way! (tested on Django 1.6)
from django.contrib.staticfiles.storage import staticfiles_storage
staticfiles_storage.url(path)
Use the default static tag:
from django.templatetags.static import static
static('favicon.ico')
There is another tag in django.contrib.staticfiles.templatetags.staticfiles (as in the accepted answer), but it is deprecated in Django 2.0+.
#dyve's answer didn't work for me in the development server. Instead I solved it with find. Here is the function:
from django.conf import settings
from django.contrib.staticfiles.finders import find
from django.templatetags.static import static
def get_static(path):
if settings.DEBUG:
return find(path)
else:
return static(path)
If you want to get absolute url(including protocol,host and port), you can use request.build_absolute_uri function shown as below:
from django.contrib.staticfiles.storage import staticfiles_storage
self.request.build_absolute_uri(staticfiles_storage.url('my-static-image.png'))
# 'http://localhost:8000/static/my-static-image.png'
In short words you need to get
STATIC_URL
STATIC_ROOT
urlpatterns
staticfiles
templatetags
url parameters
All in the right place, to get this working. In addition, in real time deployment, circumstances vary, which it is very possible that the current setting you spent 3 hours worked out, works on your local machine but the server.
So I adopted the traditional way!!
app
├── static
│ └── json
│ └── data.json
└── views.py
views.py
import os
with open(os.path.abspath(os.getcwd()) + '/app/static/json/data.json', 'r') as f:
pass

Could not import/No module named Django Error with Apache

I had a small proof of concept set up on a development server on a local machine. I'm now trying to move it over to django on a production server, which I'm using webfaction for. However, now that I'm switched over to apache from the built in django server I get the following:
ViewDoesNotExist: Could not import orgDisplay.views. Error was: No module named orgDisplay.views
But when check my orgDisplay apps folder there is a view.py in it. What am I doing wrong? I've tried adding the following to my settings.py by suggestion of the django IRC room.
import sys
sys.path.append(r"/home/user/webapps/django_project/myproject/orgDisplay")
which is the path to my app.
any ideas on how to even begin to trouble shoot this?
Thanks in advance.
I assume you're using mod_wsgi (which is recommended by Django authors), not mod_python. This is the way you should use your sys.path:
django.wsgi:
import os, sys
sys.path.append(r"/home/user/webapps/django_project/myproject/")
os.environ["DJANGO_SETTINGS_MODULE"] = "settings"
sys.stdout = sys.stderr # Prevent crashes upon print
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
urls.py:
from django.conf.urls.defaults import *
urlpatterns = (
("", include("orgDisplay.urls")),
# ...
)
orgDisplay/urls.py:
import views
urlpatterns = (
(r'^some_view/$', views.some_view), # It is actually orgDisplay.views.some_view
# many more records ...
)
It is a bad idea to add project dir itself to path since you're be getting name conflicts between multiple projects.
I think you're appending the wrong directory to sys.path. I think Python is looking in the .../myproject/orgDisplay folder for the orgDisplay package. Try removing the orgDisplay from your string, like this:
import sys
sys.path.append(r"/home/user/webapps/django_project/myproject")
The other option would be to simply add myproject (or whatever your project is actually called) in the import statement.
# instead of "from orgDisplay import views"
from myproject.orgDisplay import views
Also, make sure to restart Apache after every edit.
looking at manage.py, it does it like so:
import sys
from os.path import abspath, dirname, join
from django.core.management import setup_environ
# setup the environment before we start accessing things in the settings.
setup_environ(settings_mod)
sys.path.insert(0, join(PINAX_ROOT, "apps"))
sys.path.insert(0, join(PROJECT_ROOT, "apps"))
Provided your WSGI file is in your project directory, a slightly more flexible way is this:
import os, sys
sys.path.append(os.path.dirname(__file__))
This will enable you to change your project location later without having to modify your WSGI file.