Django MEDIA not accessible - python

My Django app is unable to see MEDIA directory. When I run one of my views I need to open a file. The scenario is to:
take a record with requested id from data base
get the file path to a file
send the file to external server for OCR purposes
urls.py
from django.conf.urls.static import static
urlpatterns = [
#my urls
] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT)
models.py
from django.db import models
from django.contrib.auth.models import User
class Homework( models.Model):
title = models.CharField(max_length = 200, default = None)
image = models.FileField(upload_to='user_scans/')
author = models.ForeignKey(User, default=None, on_delete = models.CASCADE)
latex = models.TextField(default = "No LaTeX Here")
settings.py:
from pathlib import Path
from django.conf.urls.static import static
BASE_DIR = Path(__file__).resolve().parent.parent
...
DEBUG = True
...
STATIC_ROOT = BASE_DIR / 'static'
STATIC_URL = '/static/'
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = "/media/"
views.py
import requests
import json
from django.shortcuts import render, get_object_or_404
from .models import Homework
def create_homework(request):
if request.method == 'GET':
#some GET stuff
if request.method == 'POST':
homework = Homework()
homework.title = title
homework.image = image
homework.author = author
homework.save()
id = homework.id
json_to_mathsnip(id)
....
def json_to_mathsnip(id):
homework = get_object_or_404(Homework, pk=id)
f = open(homework.image.url, "rb")
...
some later stuff
...
Unfortunately I'm constantly running into an error:
FileNotFoundError at /homework/new
[Errno 2] No such file or directory: '/media/user_scans/kwa.png'
My main concern is I can access file from localhost:8000/media/user_scans/kwa.png
and from admin panel. Requested file is saved properly:
Also settings.py configuration seems to be in tact. What might be the issue?
(env) $ pip freeze
asgiref==3.5.0
backports.zoneinfo==0.2.1
certifi==2021.10.8
charset-normalizer==2.0.12
Django==4.0.1
idna==3.3
Pillow==9.0.0
psycopg2-binary==2.9.3
requests==2.27.1
sqlparse==0.4.2
urllib3==1.26.9

This may not be the best way, but I tried it and it works. The bottom line is that when using the open() function with a relative path, such as /media/user_scans/kwa.png, then that file must be in the same directory as where the function is called. You could just find the absolute path of your image files in your computer, then append the filename to that and it will work, or you can do what I have below.
import requests
import json
from django.shortcuts import render, get_object_or_404
from .models import Homework
# ADD THESE
import os
from pathlib import Path
def create_homework(request):
if request.method == 'GET':
#some GET stuff
if request.method == 'POST':
homework = Homework()
homework.title = title
homework.image = image
homework.author = author
homework.save()
id = homework.id
json_to_mathsnip(id)
....
def json_to_mathsnip(id):
homework = get_object_or_404(Homework, pk=id)
# ADD THESE
BASE_DIR = Path(__file__).resolve().parent.parent
path_to_image_file = str(BASE_DIR) + homework.image.url
f = open(path_to_image_file, "rb")
...
some later stuff
...
When you show an image in Django, or you access its url, it is a relative path, but the root is the url root, localhost:8000/, and the image url is appended to that, and Django manages to find the file (how exactly, I don't know). But the image file is in your computer, and that is what you want to open.

Related

Django how to change where uploaded file is saved

After uploading a CSV file into a Django form and submitting, Django creates a copy of this in the project app folder. I want to be able to tell Django to store this copy in another directory. How do I do that? Thanks.
You can do something like that :
models.FileField( upload_to="YourFolder")
In your setting your can specify the folder media :
Media URL
MEDIA_URL = "/media/"
Documentation for the FileField
If you want to specify the folder at save time :
from django.shortcuts import render
from django.conf import settings
from django.core.files.storage import FileSystemStorage
def upload(request):
folder='my_folder/'
if request.method == 'POST' and request.FILES['myfile']:
myfile = request.FILES['myfile']
fs = FileSystemStorage(location=folder) #defaults to MEDIA_ROOT
filename = fs.save(myfile.name, myfile)
file_url = fs.url(filename)
return render(request, 'upload.html', {
'file_url': file_url
})
else:
return render(request, 'upload.html')

Page returns 'Not Found' when opening URL to image in deployment but works in local machine. [Django Rest Framework]

My Django REST API supposedly is able to GET and POST images. During development, I was able to save the image into the database and retrieve the saved image via the URL of the image. However, when deployed to Heroku, the page returns 'Not Found' when I clicked the URL to the image.
requirements.txt
asgiref==3.2.10
dj-database-url==0.5.0
Django==3.0.8
django-heroku==0.3.1
djangorestframework==3.11.0
gunicorn==20.0.4
Pillow==7.2.0
psycopg2==2.8.5
pytz==2020.1
sqlparse==0.3.1
whitenoise==5.1.0
settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
django_heroku.settings(locals())
urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('element.urls')),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py (Element App)
from django.db import models
# Create your models here.
class Element(models.Model):
element_name = models.CharField(max_length=255, unique=True)
element_tag = models.CharField(max_length=255)
element_type = models.CharField(max_length=255)
element_img = models.ImageField(upload_to='elements/')
creator_tag = models.CharField(max_length=255)
creator_link = models.CharField(max_length=255)
def __str__(self):
return self.element_name
serializers.py (Element App)
from rest_framework import serializers
from element import models
class ElementSerializer(serializers.ModelSerializer):
element_img = serializers.ImageField(max_length=None, use_url=True)
class Meta:
model = models.Element
fields = ('id', 'element_name', 'element_tag', 'element_type', 'element_img', 'creator_tag', 'creator_link')
views.py (Element App)
from django.shortcuts import render
from rest_framework import viewsets
from rest_framework import filters
from element import serializers
from element import models
# Create your views here.
class ElementViewSet(viewsets.ModelViewSet):
queryset = models.Element.objects.all()
serializer_class = serializers.ElementSerializer
filter_backends = (filters.SearchFilter,)
search_fields = ('element_name', 'element_tag', 'element_type',)
urls.py (Element App)
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from element import views
router = DefaultRouter()
router.register('elements', views.ElementViewSet, basename='Elements')
urlpatterns = [
path('', include(router.urls))
]
Note: The image along with its data is saved and can be seen in the admin panel. However, when opening the URL to the image, it returns 'Not Found'.
Both staticfiles and media folder are pushed into GitHub repository
When viewing in my local machine, if I open the URL to 127.0.0.1:8000/media/elements/picture.png, it returns the image. After being deployed, when I open the URL to project_name.herokuapp.com/media/elements/picture.png, it returns 'Not Found'
The problem is in serving your media files.
Django is not built to serve static and media files in production Deploying Static Files
Since your using Heroku as your hosting platform, whitenoise is able to handle your static files. However, for media files a simple fix to the problem is to set up a free Amazon S3 account to host all your media files.
Here is a quick reference guide Serving Django Media Files in Production

DJANGO - upload image stored locally to model ImageField attribute

I have my images downloaded inside the subroot images in my media folder and I'm trying to generate new models which will contain the photo inside the images folder. This is what my model and my view look like:
class Post(models.Model):
...
image = models.ImageField(upload_to="images", blank=True, null=True)
def generate_posts(request):
for i in range(20):
title_ = f'title{i}'
body_ = f'text for post number : {i}'
author_ = f'author{i}'
network_ = randomize_social()
post = Post(title=title_, body=body_, author=author_, social_network=network_)
if randomize_picture():
post.image.save("logo.png", File("images/svante.jpg"), save=True)
else:
post.image = None
post.save()
areGenerated = True
return render(request, "posts/generate_posts.html", {'areGenerated':areGenerated})
The logo.png file is created inside the images folder, but it's blank, 0kb size and when I follow the /generateposts url, I receive this error message:
AttributeError at /generateposts
'str' object has no attribute 'read'
What can I do to solve this problem?
Did you make changes to your settings file? you need to make changes such as
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
and don't forget to add these to your urls:
from . import views, settings
from django.contrib.staticfiles.urls import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

django view url mapping

I am trying to load a template from a nested directory in django but keep getting a improperly configured no pattern match error. I've attempted all combinations of folder names but the error keeps on continuing, I'm scratching my head with this one, any help? here are my files:
view.py
from django.http import HttpResponse
from django.template import loader
def index():
curTemplate = loader.get_template('/droneMapper/index.html')
return HttpResponse(curTemplate.render())
settings.py
BASE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)
TEMPLATE_DIRS = (os.path.abspath(os.path.join(BASE_DIR, 'templates')),)
the file strcture is:
root
-app
-templates
-app
-setting
I simply use this small code:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
TEMPLATE_DIRS = (os.path.join(BASE_DIR, 'templates'),)
works fine for me.

Alternative for Absolute Path in Django

I am making a Django Project, A Business Directory.
Here I have used ABSOULATE PATHS for Template rendering,
I thnk this might create problem in future.
Please look into my codes and Suggest me how to solve this problem so that it does not create any problem in future.
Please help
my models.py is::
from django.db import models
class Directory(models.Model):
Bussiness_name = models.CharField(max_length=300)
Description = models.CharField(max_length=900)
Number = models.CharField(max_length=100)
Web_url = models.CharField(max_length=800)
Catogory = models.CharField(max_length=200)
def __unicode__(self):
return self.Bussiness_name
class Adress(models.Model):
directory = models.ForeignKey(Directory)
adress_name = models.CharField(max_length=300)
def __unicode__(self):
return self.adress_name
class Photos(models.Model):
directory = models.ForeignKey(Directory)
Photo_path = models.CharField(max_length=100)
Photo_name = models.CharField(max_length=100)
def __unicode__(self):
return self.Photo_name
My view.py is ::
# Create your views here.
from django.http import HttpResponse
from crawlerapp.models import Directory
from crawlerapp.models import Adress
from crawlerapp.models import Photos
from django.template import Context, loader
from django.shortcuts import render
def index(request):
Directory_list = Directory.objects.all()
t=loader.get_template('C:/Python27/django/crawler/templates/crawlertemplates/index.html')
c = Context({'Directory_list': Directory_list,})
return HttpResponse(t.render(c))
def contactus(request):
Directory_list = Directory.objects.all()
t=loader.get_template('C:/Python27/django/crawler/templates/crawlertemplates/contactus.html')
c = Context({'Directory_list': Directory_list,})
return HttpResponse(t.render(c))
def search(request):
if 'what' in request.GET and request.GET['what']:
what = request.GET['what']
crawlerapp = Directory.objects.filter(Catogory__icontains=what)
return render(request, 'C:/Python27/django/crawler/templates/crawlertemplates/search.html',
{'crawlerapp': crawlerapp, 'query': what})
elif 'who' in request.GET and request.GET['who']:
who = request.GET['who']
crawlerapp = Directory.objects.filter(Bussiness_name__icontains=who)
return render(request, 'C:/Python27/django/crawler/templates/crawlertemplates/search.html',
{'crawlerapp': crawlerapp, 'query': who})
else:
message = 'You submitted an empty form.'
return HttpResponse(message)
And my urls.py is::
from django.conf.urls import patterns, include, url
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Examples:
# url(r'^$', 'crawler.views.home', name='home'),
# url(r'^crawler/', include('crawler.foo.urls')),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
url(r'^crawlerapp/$', 'crawlerapp.views.index'),
url(r'^crawlerapp/contactus/$', 'crawlerapp.views.contactus'),
url(r'^crawlerapp/search/$', 'crawlerapp.views.search'),
)
I have 3 html pages INDEX, CONTACTUS, and SEARCH.
Please suggest an alternative of Absolute path so that it create no errors if I someone else clones it from GITHUB and try to run it.
Please help to solve this.
You should list you're template directories in your setting.py files, in the TEMPLATE_DIRS list.
Whether you do that or not, you should dynamically generate the absolute path by using the os.path module's function.
os.path.abspath(__file__)
will return the absolute path to the file it's called in.
os.path.dirname('some/path')
will return the path to the last directory in 'some/Path'
By combining them you can get absolute pathes which will remain accurate on different systems, eg
os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
will return an absolute path to the directory one level above the one containing the current file.
Go read the docs for the os.path module. You'll probably need to use os.path.join as well.
Have you considered reading the Django tutorial?.
Don't forget to set TEMPLATE_DIRS in your settings.py file, a good tip for doing so can be found on another answer; Django template Path
In your project settings.py file:
Add this at the top
import os.path
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
Then to set template path do this:
TEMPLATE_DIRS = (
os.path.join(PROJECT_ROOT, "templates"),
)
With this you going to be in the obligation in a future to recheck your all files to change the path in case if you change directories so: in you settings.py file define:
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__),'templates').replace('\\','/'),
'/path/to/my/project/'
'/path/to/my/project/template/', # for the apps
)
Where templates/ is the directory for your templates.

Categories