Django - Can't read media files - python

I'm using Django to create a website where you can upload an image on that website and check if the image contains Moire pattern. Here is the project structure:
In file settings.py, I specified the following directory for media files:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
and in file views.py, I implemented the API that will receive the image and detect moire pattern like this:
from django.core.files.storage import default_storage
def index(request):
if request.method == 'POST':
f = request.FILES['sentFile']
response = {}
fname = 'pic.jpg'
fname2 = default_storage.save(fname, f)
file_url = default_storage.url(fname2)
image = Image.open(file_url)
pred_label = moire_detect(image)
response['label'] = pred_label
return render(request, 'frontpage.html', response)
else:
return render(request, 'frontpage.html')
However, when I try to open the image using Image module of Pillow, I got this error "No such file or directory: '/media/pic_O1TOyCK.jpg'".
I don't really understand what is happening here, because the path is correct. Any help would be really appreciated.

Image.open doesn't work with url but with normal path.
But file_url has /media/pic_O1TOyCK.jpg which is relative url and it can be used on HTML (to get http://localhost/media/pic_O1TOyCK.jpg) but it can't be used as normal path to access directly local file.
You should rather use fname2 with Image.open()

Related

How to display image file from sftp remote server in django template?

We have 2 servers. One of them is for media files and the other one is for django project server(ngnx+gunicorne).
Our media server is local(internal). We want to access to media server from inside the project with sftp storage package which includes paramiko. we don't want to access media server via URL (http,https).
HttpResponse(file, content_type=type) can display the image file as a big picture but we want to pass the image file to django template for display in html file like <img src="{{images}}" alt="">
We know HttpResponse is not a good solution but we use it below code for explained our problem.
# view
def coursesPageView(request):
courses = Course.objects.filter(is_published=True)
image_data =[imageRespone(data) for data in courses]
data = {
'published_courses_list':courses,
'images' : image_data
}
return render(request, 'pages/course2.html', data)
def imageRespone(valid_image):
if sfs.exists(valid_image.image.name):
file = sfs._read(valid_image.image.name)
type, encoding = mimetypes.guess_type(valid_image.image.name)
response = HttpResponse(file, content_type=type)
return response
else:
return HttpResponse('404 Not Found')
#course2.html
<img src="{{images}}" alt="">
What you can do is mounting a shared drive into your webserver pointing to your media server (Samba for linux). Then with Django you can specify the localisation of your statics file.
For example :
import os
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.abspath(os.path.join(os.sep, 'srv', 'media'))
STATIC_URL = '/app/static/'
STATIC_ROOT = os.path.abspath(os.path.join(os.sep, 'srv', 'static'))
Pay attention to the permissions between the web server and the mounted folder.

Upload PDF File via Django Admin, Users Download from Link on Template

I'm trying to allow users to download a PDF file that I've previously uploaded to the MEDIA_ROOT folder via the admin console. I've emulated the answer in this post, however it's incomplete and I can't figure out how to fix this. Hoping someone can spot my issue in the code below.
settings.py
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = str(BASE_DIR) + "/media/"
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = '/media/'
# Absolute path to the directory that holds static files.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = str(BASE_DIR) + "/static/"
# URL that handles the static files served from STATIC_ROOT.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
models.py
from django.db import models
# Create your models here.
class ResumeModel(models.Model):
pdf = models.FileField(upload_to="resume_app/media/resume/")
# So this file gets uploaded to root > media > resume_app > media > resume
admin.py
from django.contrib import admin
from .models import ResumeModel
# Register your models here.
admin.site.register(ResumeModel)
views.py
from django.shortcuts import render
from .models import ResumeModel
# Create your views here.
def resume(request):
resume = ResumeModel.objects.all() # < Not sure if this part is needed?
return render(request, 'resume.html', context={'resume':resume})
template.html
...
Click here to download PDF
...
When I hover over this link, the url it's pointing to is localhost:8083/resume/, which is the name of the page we're currently on, so I think the <a href="{{ resume.pdf.url }}"> is not pointing to the correct url of the PDF file I've uploaded. The upload DOES work, the file IS in the root > media > resume_app > media > resume folder. What do I need to make the link work?
UPDATE
Thanks to the help of #tonio below, and apart from my oversight, I changed the line(s):
def resume(request):
resume = ResumeModel.objects.all() # < Not sure if this part is needed?
return render(request, 'resume.html', context={'resume':resume})
to
def resume(request):
resume = ResumeModel.objects.last()
return render(request, 'resume.html', context={'resume':resume})
...which is fine for me as I will only have 1 resume in there, and the last entry will be the most recent upload. I then went into that app's folder, and deleted the __pycache__ and migrations folders, performed python manage.py makemigrations resume_app and python manage.py migrate resume_app, restarted the server, opened app in incognito window and it worked as desired!
You're sending all resume objects stored in the database to the template:
resume = ResumeModel.objects.all()
You can send an specific resume identified by their primary key (see this):
def resume(request, resume_id):
resume = get_object_or_404(ResumeModel, resume_id)
return render(request, 'resume.html', context={'resume':resume})
Anyway, you can test the template sending the first resume in the database:
def resume(request):
resume = ResumeModel.objects.first()
return render(request, 'resume.html', context={'resume':resume})

Django - Protect media files with django-wiki

In the past I managed to protect my images in other projects in the following way:
urls.py
urlpatterns = [
...
path('media/<str:filename>/', views.media, name="media"),
]
settings.py
#MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
views.py
#login_required
def media(request, filename):
import os
from mimetypes import MimeTypes
content_type, encoding = MimeTypes().guess_type(
os.path.basename(filename)
)
if content_type is None or len(content_type) == 0:
print(f'No content-type found for file: {filename}')
content_type = 'text/plain'
try:
url = os.path.join(
settings.MEDIA_ROOT, str(filename)
)
with open(url.encode('utf-8'), 'rb') as f:
resp = HttpResponse(f.read(), content_type=content_type)
# resp['Content-Disposition'] = f'attachment; filename="{filename}"'
resp['X-Robots-Tag'] = 'noindex, nofollow'
return resp
except IOError as ex:
data = {'ERROR': str(ex)}
print(data)
return JsonResponse(data)
With this, if someone tries to view for example an image via the url www.example.com/media/image.png, the user cannot see anything unless they are logged in.
I need to use the django-wiki system https://github.com/django-wiki/django-wiki which I have installed in my existing project through pip install wiki.
Now my project works together with the wiki system.
Wiki system is installed in this path:
/Users/{my_username}/.virtualenvs/{my_virtualenv_name}/lib/python3.9/site-packages/wiki/
Is there any way to protect images in the same way for the wiki system?
I think modifying .../site-packages/wiki/ views is not a good idea and perhaps there is a better solution to the problem posed.

Django: open PDF file object

in my Django app I´m trying to open and show pdf files that wasn't loaded to a model, but can´t find the appropriate way.
I have a group of PDF invoices that I manually copied to media/my_folder (I use Dropbox as media host to be able to do that).
Then I want to show each invoice when requested.
File object option
After investigating several posts, I think the way to do it is creating a file object dynamically.
invoice_path = "my_folder/" + invoice_number + ".pdf"
f = open(invoice_path, 'w')
myfile = File(f)
Then I understand the in the template I could be able to access the file as it was loaded to the model.
<p>Ver factura AFIP</p>7
I get a FileNotFoundError, I guess I´m not setting the path to media files correctly.
Exception Type: FileNotFoundError at /catalog/perfilfactura/FA B
0003-00000220 Exception Value: [Errno 2] No such file or
directory: 'media/Facturas_Electronicas/FA-B-0003-00000220.pdf'
This happens when trying to open the file. The path I set it's supposed to be relative to MEDIA_ROOT, just add the subfolder "my_folder" and then the pdf file name.
Path in template option
I also tried to set the path directly in the template as in:
<p><a href="media/{{ archivo_factura }}.pdf" download>Ver factura AFIP</a></p>
<p><a href="{{ MEDIA_URL }}Facturas_Electronicas/{{ archivo_factura }}.pdf" download>Ver factura AFIP</a></p>
In both cases I get a downloaded ampty PDFs.
My settings:
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
And my Dropbox settings:
DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage'
DROPBOX_OAUTH2_TOKEN = 'my_token'
DROPBOX_ROOT_PATH = '/Kinemed APP/'
Thanks!
There doesn't seem to be any reason to either open the file or create a File object. If your file is inside the media directory, all you need to do to create a URL for it is to join the media root:
invoice_path = os.path.join(settings.MEDIA_ROOT, "my_folder/" + invoice_number + ".pdf")
and now pass invoice_path directly to the template and access it there.

Accessing an image stored with FileStorage from a custom template tag in Django

I have used Django's FileStorage to store an image, and I have sent the url of this image from a template to a custom templatetag. But I am not able to access the image at this url.
I have also tried accessing the media directory to get the uploaded image but I get the following error:
IsADirectoryError at /
[Errno 21] Is a directory: 'media/'
views.py
def index(request):
context = {}
if request.method == "POST":
up_image = request.FILES['image']
fs = FileSystemStorage()
name = fs.save(up_image.name,up_image)
context['url'] = fs.url(name)
return render(request,"ind.html",context)
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
template ind.html
{% load testing %}
<p>{% fname url %}</p>
custom templatetag testing.py
from django import template
import webbrowser
from PIL import Image
register = template.Library()
#register.simple_tag
def fname(url):
x = url[7:] #getting only the name of the file uploaded
path = 'media/'+x
with Image.open(path) as image:
width, height = image.size
return width
I have also tried opening the image with the url passed itself but I could not get it to work.
I am just trying to access the uploaded image so I can do some further processing for it, but for now I am just returning the width of the image to check if it is working

Categories

Resources