Django model field to image in static folder - python

I am trying to make a Django model of a game with fields for a name and also a cover image that is located in the static folder of the app.
def game_covers_path():
return os.path.join(settings.STATIC_URL, 'some_app/games/')
class Game(models.Model):
name = models.CharField(max_length=100, primary_key=True)
cover = models.FilePathField(path=game_covers_path, null=True)
def __str__(self):
return self.name
My folder structure is as follows:
.
├── db.sqlite3
├── my_app
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── some_app
├── __init__.py
├── admin.py
├── apps.py
├── migrations
├── models.py
├── static
│   └── some_app
│   ├── games
│   │   ├── Counterstrike:\ Global\ Offensive.jpg
├── templates
├── tests.py
├── urls.py
└── views.py
But when I open the admin page I get the following error:
FileNotFoundError at /admin/some_app/game/add/
[Errno 2] No such file or directory: '/static/some_app/games/'
How can I correctly reference images in the static folder of an app in the database? Also does the FilePathField check if the a file exists before saving a model? Because I tried adding random values and it saved it, but in the documentation its written that you can only choose a file that already exists...

(too long for comment)
STATIC_URL is an URL which will be mapped to STATIC_ROOT path by Django in runtime, so use STATIC_ROOT to build file path
static files are not supposed to be dynamically modified: css, js, favicon; what you are trying to do is called media files in terms of Django so use to MEDIA_URL, MEDIA_ROOT instead. Also note, whereas static files are fine to be stored in project folder, media files are usually stored somewhere else. They are not part of your project/solution - they are data.
To handle properly both static and media files you must configure STATIC_ROOT, STATIC_URL, MEDIA_ROOT, MEDIA_URL
There are dozens of questions and answers related to Django static and media files here on SO, please have a look at them. And please take a look at the docs.

Related

Openshift Find Static Files From Django App

I am trying to add a css file to my django application which I am deploying on openshift. Currently, I am able to have the css file work when running locally with debug and all that. However, when I deploy my application to openshift, the css file does not have any effect. Many of the other questions online seem to be referring to old versions of django and openshift (lots of references to a wsgi folder that doesn't seem to be standard anymore and triggering collectstatic manually)
My understanding with the current django/openshift relationship is that I do not need to do collecstatic manually as I am using the django-ex template from openshift, and during the build process the collectstatic command is run automatically, the ouput of which I can see in the logs. Notably, I can see that my style.css file for my application gets copied into STATIC_ROOT in that log.
My project structure from my project root is thus:
.
├── db.sqlite3
├── djangoWrapper
│   ├── __init__.py
│   ├── settings.py
│   ├── templates
│   │   └── djangoWrapper
│   │   └── index.html
│   ├── urls.py
│   ├── views.py
│   └── wsgi.py
├── gitlab-ci.yml
├── ldap
│   ├── admin.py
│   ├── apps.py
│   ├── forms.py
│   ├── __init__.py
│   ├── migrations
│   ├── models.py
│   ├── static
│   │   └── ldap
│   │   └── style.css
│   ├── templates
│   │   └── ldap
│   │   ├── apiOffline.html
│   │   ├── index.html
│   │   ├── results.html
│   │   └── search.html
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── manage.py
├── openshift
├── README.md
├── requirements.txt
Here's what I am doing in my settings.py:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, "ldap", "static"),]
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
In my html files, I am then trying to load the css file with
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'ldap/style.css' %}">
in the <head> section.
I have attempted to do some debugging here because it would be assumed that the problem before I got to deployment was that my static files were not being put in the correct place/djgano couldn't find them. So I put some prints into my app and deployed it on openshift and got back the following info:
BASE_DIR: /opt/app-root/src
STATIC_ROOT: /opt/app-root/src/static
STATIC_URL: /static/
APP_VIEW_DIR: /opt/app-root/src/ldap/views.py
as well putting <p>"{%static 'ldap/style.css' %}"</p> into an html file, which displays as /static/ldap/style.css
From these tidbits, I know that the root directory for openshift is /opt/app-root/src/, that my static files are in /opt/app-root/src/static, and that my html is looking for the css file in /static/ldap/style.css. This seems like it should be working then as all of those directories line up. Is there something else about serving static files with django/openshift that I am missing here?
Finally got it working! I did use whitenoise, following the steps here.

Django: reusable templates: extend from base.html

What is the most reusable way for the "extends" method in django templates?
I have seen this very often:
{% extends 'base.html' %}
Unfortunately this does not work for me. The ordering of the template loader loads a template from a different app first.
I have a default django project and application created from scratch with Django1.8.
What should I do:
use a different name like 'my_base.html'
alter the ordering of the template loader
other solution?
The easy way to solve this problem is to namespace your templates. Create an application and inside the application directory (where you have the default views.py) create a templates directory, and inside that directory create a subdirectory which is the name of the application.
Imagine you have a project myproj and an app called registration, then you would have:
.
├── manage.py
├── myproj
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── registration
├── admin.py
├── __init__.py
├── migrations
│   └── __init__.py
├── models.py
├── templates
│   └── registration
│   └── base.html
├── tests.py
└── views.py
Now even if you have another application with a template called base.html, you can always load the specific template you need with {% extends 'registration/base.html' %}

How to reference static file in Django app's view

I know there have been many questions here on accessing static files in a Django project, but I could not find a satisfactory answer to a problem I am dealing with. So, here's my project structure:
.
├── project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
├── db.sqlite3
├── manage.py
└── app
├── admin.py
├── __init__.py
├── migrations
│   ├── __init__.py
├── models.py
├── static
│   └── app
│   └── file.txt
├── tests.py
├── urls.py
└── views.py
As per Django 1.7 documentation I have stored the static file file.txt in app/static/app folder. Now, how do I reference this file in a view? Lets just say I need to read the contents of this file for every call defined in app/views.py.
As usual, I have default setting of STATIC_URL = '/static/' in project/settings.py
Thanks
You can import the static template tag into your view and use it as such:
from django.templatetags.static import static
url = static('app/file.jpg')
You can do this by defining STATIC_ROOT in your settings. Then before running your project you can run
python manage.py collectstatic
And the static files then can be accessed using:-
file = open(os.path.join(settings.STATIC_ROOT, 'app/a.txt'))
This is basically the way, it is supposed to be done in a production environment, as static files are hosted separately from the django html views.
To load the name of app dynamically in project/urls.py
url(r'^', include('app.urls', app_name="app")),
and then in views:-
from django.core.urlresolvers import resolve
def appname(request):
return resolve(request.path).app_name

Flask url_for incorrectly links to static pages outside of templates

I'm currently in the process of moving all of my static files to S3, as well as allowing some image uploads to my site. In general this is going fantastically. I got all of my existing css and js files up to S3 with no hassle, however I'm having some trouble with uploading images and saving them to S3.
Specifically this is how I'm handling file uploads within my view:
image_file = request.files["imageurl"]
if image_file and allowed_file(image_file.filename):
fn = "products/%s" % secure_filename(image_title + "." + image_file.filename.split(".")[-1])
image_file.save(url_for('static', filename=fn))
else:
response = app.make_response(render_template(
'admin/newImage.html',
title=title,
error="That Image file is invalid.")
)
return response
Which is all wrapping in a POST request handler. The problem here is that the url_for('static') fails to link to the correct path, and so I get an IOError anytime I try to save an image like this.
Normally I would assume I was just doing something silly with my directory structure, but the same pattern of url_for works perfectly for files in my static directory. Any ideas on how to remedy this? Here's my directory structure (trimmed down for viewing)
├── SpoolEngine
│   ├── admin.py
│   ├── __init__.py
│   ├── templates
│   │   ├── admin
│   │   │   ├── base.html
│   │   ├── base.html
│   │   ├── _forms.html
│   │   ├── posts
│   │   │   ├── complete.html
│   │   └── super_user
│   │   ├── base.html
│   ├── users.py
│   └── views.py
└── static
├── css
│   ├── admin.css
│   └── zebraTable.css
├── img
│   └── subtle_grunge.png
├── js
│   ├── compatibility.js
│   ├── list.js
│   ├── login.js
│   └── profiler.js
└── products
And for reference, url_for works perfectly within /static/css and links to the wrong url from admin.py Any ideas?
url_for returns an url path. Not a filesystem path.
So you're trying to save your file at /static/something which, for the system, means a path starting from the root of your filesystem, not your application path.
You can create the static path for your file with something like this
static_path_to_save = os.path.join([app.root_path, '/static', fn])
Just a side note, when dealing with uploads, remember to sanityze all the paths and to double check the destination. Best practices applies, like stripping slashes if you use the filename provided by the user (best is if you generate the filename).
In your code I see also a problem if 2 users uploads a file with the same name, overwriting each other. But this is probably safe in your context.

Django tutorial customize admin template

I'm working through the official Django tutorial. At the end of part two they have you customize the admin template just a bit (changing some heading text). I think I've done everything right, but apparently I haven't because the admin site looks exactly the same after running syncdb and restarting the server. My project directory (excluding the virtualenv part) looks like this:
mysite
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── settings.py
│   ├── settings.pyc
│   ├── urls.py
│   ├── urls.pyc
│   ├── wsgi.py
│   └── wsgi.pyc
├── polls
│   ├── admin.py
│   ├── admin.pyc
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── models.py
│   ├── models.pyc
│   ├── tests.py
│   └── views.py
└── templates
└── admin
└── base_site.html
In settings.py I have these lines added to make the project use the template in templates/admin:
import os
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
later:
TEMPLATE_DIRS = (os.path.join(PROJECT_PATH, 'templates'),)
I've tried several combinations of slashes and variations on assigning the value to PROJECT_PATH and TEMPLATE_DIRS, but haven't gotten anything to work. Each time I verified that it was actually making a filepath string (with a simple print statement).
To try to see what was going on I edited the original Django base_site.html it its admin folder and that changed my site, so it's obviously still using that. I've read several SO posts, and I don't really know what to do anymore.
Oh, and if it's relevant: Python 2.7.3 and Django 1.4.3
First thing I would try is deleting your *.pyc files they often contain stale information which sometimes can cause issues likes this.
If that isn't the case I would then double check your PROJECT_PATH which I believe is the issue here.
dirname gets you the containing directory. so if that line is in the settings.py it will return /path/to/inner/mysite the one inside the main mysite and since there is not templates directory in your inner mysite it wont work.
what you need to do is this.
PROJECT_PATH = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
Which will return you the outer mysite path when combined with templates it will return you the correct path.
Everything should then work.

Categories