Django - ImageField, upload, store and serve image in development server - django

I'd like to have an ImageField in the admin form for my model (say, for an individual's profile). And I'd like to display this image in a view later on.
This is the model I have :
class Individual(models.Model):
ind_name = models.CharField(max_length=100)
ind_photo = models.ImageField(default="default.jpg")
def __str__(self):
return self.ind_name
This is what I have in the settings for my website :
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static")
MEDIA_URL = '/static/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,"static/media")
These are the urls of my app:
urlpatterns = [
url(r'^$', views.index, name="index")
]
I know how to use static files (e.g. CSS, Javascript), and to get them to work in both development and production.
But I have no clue how to get images to work. I've read Managing static files and Deploying static files, but I still don't get it.
With the code above the image gets saved in the proper folder (i.e. /static/media at the level of my site). But I have no clue :
1) how to display it in a template,
2) whether it would be best to keep these images in my app's static folder,
3) and (if 2) whether I would need to run collectstatic every time someone uploads an image in the admin.
Sorry if I'm unclear, but this way more obscure than I thought it would be.

In order for the image to be uploaded and served during development, I had to move the media folder out of the static folder (i.e. create a media folder at the root of my project's folder).
And in my main urls.py, I had to add :
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
as suggested by MicroPyramid.
To display it in a template, for a given Individual "somebody" (from a queryset), I use :
<img src="{{ somebody.ind_photo.url }}">

It is good practice to separate both staticfiles and media files. Yes, you have to do collectstatic all the time when you upload if you store the images in static folder. We can get the image full url from the object like the following.
{{obj.ind_photo.url}}
For more info on files https://docs.djangoproject.com/en/1.10/topics/files/

Related

Difference between static files and media files: How to show some upload image in template

I am new to Django and still struggling to grasp static files and media files.
IF i want have images that are stored in models with mode.FilePathField on my website that are static then how should i call them properly in my templates:
using static tag Like that:{% static project.image.path %}
or that just by calling it: {{ project.image.path }}
When reading tutorial i got answers that the first one but then it doesn't work. It gives me wrong paths
i will get 'static/MyApp/static/Myapp/img.jpg' instead of MyApp/static/Myapp/img.jpg
I would be really glad for an example of static files called dinamacally.
According with django doc here
Web App generally need to serve additional files such as images, JavaScript, or CSS. In Django, he refer to these files as static files. Django provides django.contrib.staticfiles to help you manage them.
On the other hand files which are uploaded by the user are called Media or Media Files.
a - When you want to serve static files that's what you have to do first:
1- Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS
2- In your settings.py file of your project, define STATIC_URL const like this: STATIC_URL = '/static/'
3- In your templates, use the static template tag to build the URL for the given relative path using the configured STATICFILES_STORAGE as follow:
{% load static %}
<img src="{% static 'my_app/example.jpg' %}" alt="My image">
4- Store your static files in a folder called static in your app. For example my_app/static/my_app/example.jpg.
5- In developpement you must add following snippet:
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
B - Now When you want to serve media files you have to do this:
1- Make sure that django.contrib.staticfiles is included in your INSTALLED_APPS
2- In your settings.py file of your project, define MEDIA_URL const and MEDIA_ROOT const like this:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
3- In developpement server you must add following snippet:
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
4- inside your template i you have to get your media files (Example show your image) you must use url attribut of your model filefield:
<img src="{{app_model.model_file_field.url}}" other attribute >

Django turns absolute filepaths into relative, forcing the server to be run from the project folder

I'm trying to create a website where you can add images to models, which will then be in turn loaded on the homepage. However, I've noticed that when I run my server, it tries to get images from my /home folder.
Here's my models.py:
image_directory = join(settings.STATICFILES_DIRS[0], "website/images")
class Item(models.Model):
image = models.FilePathField(path=image_directory, recursive=True)
Here's my home.html (I'm just abbreviating it, item is passed in OK:
<img src="{{ item.image }}">
I run the migrations and run the server, and I'm able to select the image in /admin. The images look like: "sub_img_folder/img.jpg"
Then I go to /home and I get the following errors:
Not Found: /home/...absolute-path-to-project.../static/website/images/sub_img_folder/img.jpg
Not Found: /home/static/website/images/sub_img_folder/img.jpg
Any help would really be appreciated.
EDIT: Here's some of my settings.py contents.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
...
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
...
MEDIA_ROOT = os.path.join(BASE_DIR + "/static/website/")
MEDIA_URL = "images/"
EDIT 2: Just to clarify, the images you add to models are already on the server. You just need to clarify which image in the admin page, hence FilePathField instead of FileField. It somehow doesn't find the image when trying to load it on the home page but it successfully shows and selects in the admin page.
EDIT:
Since you are using a FilePathField, it only stores the path on disk, not the URL. The solution would be to use the MEDIA_URL in your template to formulate the URI string, something like this:
<img src="{{ MEDIA_URL }}/{{ FILE_NAME}}">
Where MEDIA_URL is your Media URL from settings.py and FILE_NAME is the name of the file itself.
It may be better to use an actual ImageField or FileField which stores all the information you need, or just have a CharField with the file name and build the URL like above.
PREVIOUS ANSWER:
Try adding the MEDIA elements to your Django settings.py. MEDIA_ROOT and MEDIA_URL tell Django how to handle user uploaded files:
In your settings.py:
MEDIA_ROOT = "/path/to/media/folder"
MEDIA_URL = '/media/'
In your urls.py:
urlpatterns = [
.......
] += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Documentation:
https://docs.djangoproject.com/en/3.0/ref/settings/#media-root

Django Media files "Could not load image" with 200 status response

I'm slightly new to Django and I'm having an issue with the ImageField field type in development environment. I'm able to upload images through the admin panel, and I have them going to my media folder location locally. But they will not render in the DOM from Django.
I'm running Django 2.1.7 and have Pillow 5.4.1 installed
My media folder is located in my base directory (same level as my manage.py file), and has a sub-directory of series (as created by my model), with all of the correct images I uploaded through the admin panel.
Within my template .html file, I am trying to load the image with:
{% load static %}
<img src="{{ s.cardImage.url }}">
And I get a 200 status response in the terminal, but the image does not render and when I inspect the image, it says "Could not load image". If I simply output {{ s.cardImage.url }} within my template, I get this path: /media/series/IMG_5776.PNG.
So I'm inclined to think that my views are correct and I'm querying the correct object from my database.
When I uploaded the image within the Admin panel, this is what it looks like: Admin Panel
If I click on that link within the admin panel (from picture above) series/IMG_5776.PNG, it takes me to this url: http://127.0.0.1:8000/media/series/IMG_5776.PNG and the DOM is blank (with a 200 status code returning from my development server).
This is where I am stumped. I've done a lot of research and I feel like I have everything properly set-up. Does anyone know what could possibly be going wrong? Help is greatly appreciated.
Relevant Settings:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Model:
class Series(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=50)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
cardImage = models.ImageField(upload_to='series', default='default.jpg')
Terminal Log:
"GET /media/series/IMG_5776.PNG HTTP/1.1" 200 0
Base urls.py:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Can't cope with images uploaded by a user during development

Django 1.9.7
Could you help me cope with user uploaded images. I have managed to save images.
But I can't show them. So far this is all about development stage (not production).
The bottommost code sample shows the html when I execute "View page source" in Chrome. This "src="/home/michael/workspace/..." is absolute path. It will work if I create such html and open it in the browser without a webserver.
But whey I run the Django dev server, the image doesn't show.
Could you give me a kick here.
/pharchive/pharchive/settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, '../media/')
MEDIA_URL = os.path.join(BASE_DIR, '../media/')
/pharchive/pharchive/urls.py
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
/pharchive/masterdocument/models.py
class Image(AbstractDocument):
image = models.ImageField(upload_to='images/%Y/%m/%d')
/pharchive/masterdocument/views.py
class ImageDetailView(DetailView):
model = Image
/pharchive/masterdocument/templates/masterdocument/image_detail.html
<html>
<img src="{{ object.image.url }}"/>
</html>
view-source:http://localhost:8000/images/6/
<html>
<img src="/home/michael/workspace/pharchive/media/images/2016/06/29/Screenshot_from_2016-02-23_205205.png"/>
</html>
MEDIA_URL should be the root URL for uploaded media, for example:
MEDIA_URL = '/media/'
You have set it to the path the the folder where uploaded media are copied.
Edit: as requested more information on how that works.
What you are trying to do is store an image file submitted by a user, and then serve it to other users. To store the file, you need to specify a location on the filesystem where to store it, in your case:
/home/michael/workspace/pharchive/media/images/2016/06/29/Screenshot_from_2016-02-23_205205.png
Django builds this path by concatenating these parts:
the MEDIA_ROOT
the ImageField's interpolated upload_to attribute, here 'images/%Y/%m/%d' interpolated to images/2016/06/29
the file name, here Screenshot_from_2016-02-23_205205.png.
Django also stores in the database the path to the file, relative to the MEDIA_ROOT, in your case images/2016/06/29/Screenshot_from_2016-02-23_205205.png
Now, to serve the stored file to your users, it first needs to be accessible through a URL, this URL is built by concatenating the MEDIA_URL setting to the path stored in the database (maybe modified to make it URL compatible), here it gives /media/images/2016/06/29/Screenshot_from_2016-02-23_205205.png.
The last step is to actually serve the file when the previously constructed URL is accessed, typically it will not be done the same way in development and in production.
In development, the Django devserver will be used to serve the file, which is why you add a url pattern when DEBUG is true. That url pattern will map any URL starting with the MEDIA_URL (/media/) to a view that will read the stored file and return its content.
In production you will use a dedicated web server to serve uploaded files, for performance reasons.

upload images to template directory

I have a model with this field:
image=models.ImageField(upload_to='company-category')
company-category is a folder in uploads folder,but I want to upload images to template directory .I think this way users that visit my website can't access images and download them.
in settings:
TEMPLATE_DIRS = (
"C:/ghoghnous/HubHub/Theme"
)
how can I do this?
Here I'm giving two solutions. The one you asked and then my suggestion.
Use the following code to set the upload location to your templates folder.
from django.conf import settings
image=models.ImageField(upload_to = settings.TEMPLATE_DIRS[0])
The above code will upload image to your template directory.
My Suggestion:
Upload images to your media folder. Then use the MEDIA_URL to allow users to download them. Use the following code to define them.
settings.py
MEDIA_ROOT = 'C:/ghoghnous/HubHub/media'
MEDIA_URL = 'site_media'
urls.py
from django.conf import settings
urlpatterns += patterns('',
url(r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
)
models.py
class SampleModel(models.Model):
image = models.ImageField(upload_to = 'images')
If you use this, the images will be uploaded to the folder C:/ghoghnous/HubHub/media/images/. Then get your required images by using objects.get or objects.filter.
record = SampleModel.objects.get(id = 1)
If I print record.image, the output will be images/filename.jpg.
Pass this to your template. Then you can display the image or give download link as follows:
<a href="{{ record.image.url }}/" >Download</a> #Download link
<img src="{{ record.image.url }}/" /> #To display image
<a href="/site_media/images/file.jpg" >Download</a> #Download static files
I suggest you using the second method, since saving images in templates folder is not adviced.
Template directory is not a preferred place to store media as per Django good practices.
Also, any images that you display on the web page will have a path and can be downloaded. Some people use scripting to stop right clicks and stuff like this but as far as I understand source code always give you image paths.
Oh, I think you'd like to upload the file to a temporary folder and then do something with it. Right?
You need to override method clean_image in forms. Then you can write your own code with any path you want using File storage