Using static images with sorl-thumbnail - django

I am trying to serve the thumbnail of a file that resides in my STATIC_ROOT folder. It doesn't really matter if it ends up in MEDIA_URL/cache, but sorl-thumbnail will not load the image from the static folder.
current code:
{% thumbnail "images/store/no_image.png" "125x125" as thumb %}
hack that works
{% thumbnail "http://localhost/my_project/static/images/store/no_image.png" "125x125" as thumb %}
I don't like the hack because
A) It is not dry (my project is actually served from a sub-directory of /
B) It is using http to grab a file that is only 3 directories away, seems pointlessly inefficient

I worked around this by passing through a file to the template context from my view.
Here is an example util function I called from my views:
def get_placeholder_image():
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
placeholder = storage.open(settings.PLACEHOLDER_IMAGE_PATH)
image = ImageFile(placeholder)
image.storage = storage
return image
You could probably do something similar as a custom template tag.

Template filter works. But I am not sure, whether there is each time reading from storage. If so, it is unreasonably...
from django.template import Library
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
register = Library()
#register.filter
def static_image(path):
"""
{% thumbnail "/img/default_avatar.png"|static_image "50x50" as img %}
<img src="{{ MEDIA_URL }}{{img}}"/>
{% endthumbnail %}
"""
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
image = ImageFile(storage.open(path))
image.storage = storage
return image

Assuming you are using Django 1.3 you should take a look at the docs about Managing static files
If you setup everything correctly, you can include your images like this:
<img src="{{ STATIC_URL }}images/store/no_image.png" />

I ended up hijacking the fact that it can get from a URL, and wrote my own tag that overrides the _render method on the ThumbnailNode:
from django.template import Library
from django.contrib.sites.models import Site
from django.contrib.sites.models import get_current_site
from sorl.thumbnail.templatetags.thumbnail import ThumbnailNode as SorlNode
from sorl.thumbnail.conf import settings
from sorl.thumbnail.images import DummyImageFile
from sorl.thumbnail import default
register = Library()
class ThumbnailNode(SorlNode):
"""allows to add site url prefix"""
def _render(self, context):
file_ = self.file_.resolve(context)
if isinstance(file_, basestring):
site = get_current_site(context['request'])
file_ = "http://" + site.domain + file_
geometry = self.geometry.resolve(context)
options = {}
for key, expr in self.options:
noresolve = {u'True': True, u'False': False, u'None': None}
value = noresolve.get(unicode(expr), expr.resolve(context))
if key == 'options':
options.update(value)
else:
options[key] = value
if settings.THUMBNAIL_DUMMY:
thumbnail = DummyImageFile(geometry)
elif file_:
thumbnail = default.backend.get_thumbnail(
file_, geometry, **options
)
else:
return self.nodelist_empty.render(context)
context.push()
context[self.as_var] = thumbnail
output = self.nodelist_file.render(context)
context.pop()
return output
#register.tag
def thumbnail(parser, token):
return ThumbnailNode(parser, token)
Then from the template:
{% with path=STATIC_URL|add:"/path/to/static/image.png" %}
{% thumbnail path "50x50" as thumb %}
<img src="{{ thumb.url }}" />
...
Not the neatest solution... :-/

The default value of setting sorl THUMBNAIL_STORAGE is the same settings.DEFAULT_FILE_STORAGE.
You must create storage that uses STATIC_ROOT, for example you can use 'django.core.files.storage.FileSystemStorage' and instantiate with location=settings.STATIC_ROOT and base_url=settings.STATIC_URL
Only THUMBNAIL_STORAGE set in settings for a 'MyCustomFileStorage' did not work. So I had to do to DEFAULT_FILE_STORAGE and it worked.
Define in settings.py:
DEFAULT_FILE_STORAGE = 'utils.storage.StaticFilesStorage'
utils/storage.py:
import os
from datetime import datetime
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.exceptions import ImproperlyConfigured
def check_settings():
"""
Checks if the MEDIA_(ROOT|URL) and STATIC_(ROOT|URL)
settings have the same value.
"""
if settings.MEDIA_URL == settings.STATIC_URL:
raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
"settings must have different values")
if (settings.MEDIA_ROOT == settings.STATIC_ROOT):
raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
"settings must have different values")
class TimeAwareFileSystemStorage(FileSystemStorage):
def accessed_time(self, name):
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
def created_time(self, name):
return datetime.fromtimestamp(os.path.getctime(self.path(name)))
def modified_time(self, name):
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
class StaticFilesStorage(TimeAwareFileSystemStorage):
"""
Standard file system storage for static files.
The defaults for ``location`` and ``base_url`` are
``STATIC_ROOT`` and ``STATIC_URL``.
"""
def __init__(self, location=None, base_url=None, *args, **kwargs):
if location is None:
location = settings.STATIC_ROOT
if base_url is None:
base_url = settings.STATIC_URL
if not location:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_ROOT setting. Set it to "
"the absolute path of the directory that holds static files.")
# check for None since we might use a root URL (``/``)
if base_url is None:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_URL setting. Set it to "
"URL that handles the files served from STATIC_ROOT.")
if settings.DEBUG:
check_settings()
super(StaticFilesStorage, self).__init__(location, base_url, *args, **kwargs)
Reference:
https://github.com/mneuhaus/heinzel/blob/master/staticfiles/storage.py
https://docs.djangoproject.com/en/dev/ref/settings/#default-file-storage

Related

loading local files in django

I have a folder in c:\images, images here are updated by another app. Then I wanted a Django application to read those images on the admin site. The django applicationis sitting in c:\inetpub\wwwroot\myapp I have tried adding below lines in settings.py
CURRENT_PATH = os.path.abspath(os.path.dirname(__file__))
MEDIA_ROOT = os.path.join(CURRENT_PATH, '../../images').replace('\\','/')
MEDIA_URL = 'images/'
I also tried including the whole path in django admin as below in admin.py
def img_field(self, obj):
return format_html('<img src="{}" width="500" height="500" />'.format("c:\images\phot1.png"))
If i put online image link it works fine as below:
def img_field(self, obj):
img = "https://www.thebalancesmb.com/thmb/5G9LJXyFzbTVS-Fj_32sHcgJ8lU=/3000x0/filters:no_upscale():max_bytes(150000):strip_icc():format(webp)/start-online-business-with-no-money-4128823-final-5b87fecd46e0fb00251bb95a.png"
return format_html('<img src="{}" width="500" height="500" />'.format(img))
How can i get around this?
I got it I just needed to add the below lines in urls.py
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
#urls here
]
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
It is working fine.

Download BinaryFiled Data

how to download BinaryField Data/file using template. like we did for FileField.
<td><a href={{certificate.bytes.url}} download></a>
I past all url.py and view.py file below please look This may give extract view of my code. and please help me with this i am new to Django. ............................................................................................................................................................
url.py
from django.conf.urls.static import static
from django.conf.urls import url
from django.views.defaults import page_not_found
urlpatterns=[
path('',views.index, name = 'index'),
url(r'^list/$', views.list, name='list'),
url(r'^list/create$', views.certificate_create, name='certificate_create'),
url(r'^list/(?P<id>\d+)/update$', views.certificate_update, name='certificate_update'),
url(r'^list/(?P<id>\d+)/delete$', views.certificate_delete, name='certificate_delete'),
path('download',views.download, name = 'download'),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
So, we need Django models which contains BinaryField for example.
models.py
class Person(models.Model):
name = models.CharField(max_length=55)
surname = models.CharField(max_length=55)
image = models.BinaryField()
class Meta:
db_table = 'person'
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('download/<int:pk>/', views.download, name='download'),
]
views.py
import io
from django.shortcuts import render
from django.http import FileResponse
from .models import Person
def index(request):
# there are listed all models.
persons = Person.objects.all()
return render(request, 'index.html', {'persons': persons})
def download(request, pk):
# this url is for download
try:
obj = Person.objects.get(pk=pk)
except Person.DoesNotExist as exc:
return JsonResponse({'status_message': 'No Resource Found'})
get_binary = obj.image
if get_binary is None:
return JsonResponse({'status_message': 'Resource does not contian image'})
if isinstance(get_binary, memoryview):
binary_io = io.BytesIO(get_binary.tobytes())
else:
binary_io = io.BytesIO(get_binary)
response = FileResponse(binary_io)
response['Content-Type'] = 'application/x-binary'
response['Content-Disposition'] = 'attachment; filename="{}.png"'.format(pk) # You can set custom filename, which will be visible for clients.
return response
index.html
{% for person in persons %}
{{ person.name }}<br />
{% endfor %}
This is solution to send binary file from server and download. All components are shown. Good luck !

I want to run machine learning algorithm using django but django is not taking csv file path

I am creating spam detection system in django in my application from homepage i will enter any string and that string will go to ml function and that function return either string is spam or ham and that result will print on next page but i am not able to define pata of csv file in pd.read_csv function. it is showing error '../data/spam.csv' does not exist: b'../data/spam.csv'
view.py file
def hompage(request):
form = DetectForm(request.POST)
return render(request, 'index.html', {'form': form})
def result(request):
form=DetectForm(request.POST)
if form.is_valid():
x=form.cleaned_data['msg']
y=machine(x)
return render(request, 'result.html',{'msg':y})
ml.py file
def machine(stringx):
import pandas as pd
import numpy as np
import re
from nltk.stem.porter import PorterStemmer
from nltk.corpus import stopwords
data = pd.read_csv('../data/spam.csv', encoding='latin-1')
data = data.iloc[:, [0, 1]]
data['v1'] = data.v1.map({'ham': 0, 'spam': 1})
courpas = []
# data_cleaning
string = stringx
df2 = pd.DataFrame({"v1": [0],
"v2": [string]})
data = data.append(df2, ignore_index=True)
# data_cleaning
for a in data['v2']:
review = re.sub('[^a-zA-Z]', ' ', a)
review = review.lower()
review = review.split()
ps = PorterStemmer()
review = [ps.stem(x) for x in review if not x in stopwords.words('english')]
review = ' '.join(review)
courpas.append(review)
# create a bag of word model
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer(max_features=5000)
x = cv.fit_transform(courpas).toarray()
y = data.iloc[:, 0].values
x_train, ytrain = x[:-1], y[:-1]
x_test, y_test = x[5572:5573], y[5572:5573]
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
classifier = GaussianNB()
classifier.fit(x_train, ytrain)
y_pred = classifier.predict(x_test)
if y_pred == 1:
return 'spam'
else:
return 'ham'
result.html file
{% block title %}
<h2>Result</h2>
{% endblock %}
{% block content %}
<p>{{msg}}</p>
{% endblock %}
url.py file
from django.conf.urls import url
from . import views
from django.urls import path
app_name = "spam"
urlpatterns=[
url(r'^',views.hompage,name='hompage'),
]
if the data folder is the root directory of project then
data = pd.read_csv('data/spam.csv', encoding='latin-1') will do the job
or you can create the path using BASE_DIR variable using
then use this variable in your views
data_dir = os.path.join(BASE_DIR, 'data') # place this in settings.py
in views
from django.conf import settings
data = pd.read_csv(settings.data_dir + 'spam.csv', encoding='latin-1')

Creating a file uploading system in Django

In my Django application I intend to create a file uploading system which puts the user uploaded files in a data folder. In order to do this I followed online tutorials Link 1 Link 2 and coded a below simple application. But it is producing error
PermissionError: [Errno 13] Permission denied: '/data'
Project Structure
<project_name>
|--data
|--<app_name>
|--<project_name>
|--manage.py
index.html
<div class="custom-file">
<input type="file" class="custom-file-input" id="fileupload" name="fileupload" multiple required>
<label class="custom-file-label" for="fileupload">Choose files</label>
</div>
view.py
from django.core.files.storage import FileSystemStorage
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def upload(request):
files = request.FILES.getlist('fileupload')
fs = FileSystemStorage(location="/data/upload/")
for fl in files:
fs.save(fl.name, fl)
settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'data')
Creating multiple file upload should handle in the form.
Take a look at Uploading multiple files
In your forms.py
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
In your views.py
from django.views.generic.edit import FormView
from .forms import FileFieldForm
class FileFieldView(FormView):
form_class = FileFieldForm
template_name = 'upload.html' # Replace with your template.
success_url = '...' # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('file_field')
if form.is_valid():
for f in files:
... # Do something with each file.
return self.form_valid(form)
else:
return self.form_invalid(form)

Separate domain for separate apps on django

I'd like to separate some apps on my website, and move some on differents domains.
But I'd like to avoid rewriting the urls in all the templates.
Is there an easy way to do this ?
The idea was to rewrite the reverse function (and thus, all the url dispatching thing).
Then, you have the first website called 'foo.com' and the second named 'bar.com'
This works for more sites than just two
app/urls.py
#!/usr/bin/python
# coding: utf-8
from django.conf.urls import include, url
from foo import urls as foo_urls
from bar import urls as bar_urls
url_patterns = [
url(r'^foo/',
include(foo_urls),
namespace='foo'),
url(r'^bar/',
include(bar_urls),
namespace='bar'),
]
app/__init__.py
#!/usr/bin/python
# coding: utf-8
"""
Just to simplify the multi website thing. Everything is served from one instance
"""
from __future__ import absolute_import
from django.core import urlresolvers
from django.http import Http404
from .settings LANGUAGES
old_reverse = urlresolvers.reverse
def remove_prefix(s, prefix):
return s[len(prefix):] if s.startswith(prefix) else s
def new_reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
""" Return an url with the domain if the page is situated on another domain
Note that this works for urls templatetags and for
django.core.urlresolvers.reverse, that are used a lot in get_absolute_url()
methods.
"""
old_reverse_url = old_reverse(viewname, urlconf, args, kwargs, current_app)
splitted_url = old_reverse_url.split('/')
if splitted_url[1] in [L[0] for L in LANGUAGES]:
(trash, lang, app, *path) = splitted_url
else:
(trash, app, *path) = splitted_url
lang = ''
if app == 'admin' or current_app == 'admin':
# fix a case where sometime the reverse has or has not a trailing /
old_reverse_url = remove_prefix(old_reverse_url, '/')
# fix a case where sometime the reverse has a double admin at the
# begining
old_reverse_url = old_reverse_url.replace('adminadmin', 'admin')
return '/%s' % old_reverse_url
path = '/'.join(path)
if lang == '':
return '//%s.com/%s' % (app, path)
else:
return '//%s.com/%s/%s' % (app, lang, path)
urlresolvers.reverse = new_reverse
templates examples
<a href="{% url 'foo:index' %}*>foo index</a>