Upload an image and display it on a webpage with Django - python

I'm new at Django and I've been following the django tutorial "djangogirl" but i wanted to add pictures so I did a model.py like this:
class Post(models.Model):
author = models.ForeignKey('auth.User')
image = models.ImageField()
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
This is my view.py:
def posts(request):
posts = Post.objects.order_by('published_date')
return render(request, 'my_blog/posts.html', {'posts': posts})
And my_blog.html:
{% extends 'my_blog/base.html' %}
{% load staticfiles %}
{% block content %}
<link rel="stylesheet" href="{% static 'style/css/posts.css' %}">
<div id="postsContainer">
<div id="posts">
{% for post in posts %}
<div>
<h3 class="date">Published the: {{ post.published_date }}</h3>
<h1>{{ post.title }}</h1>
<img src="{{ post.image.url }}"/>
<p>{{ post.text|linebreaks }}</p>
</div>
<div id="button">
<button type="button" class="btn btn-primary">Read more</button>
</div>
<div class="top-divider"></div>
{% endfor %}
</div>
</div>
{% endblock %}
And I insert my image via the Django admin page.
The problem is the URL that is returned in my HTML is really weird like: ./images_SseHlrA.png and it doesn't obviously display the picture correctly. How can I fixed it?
Apparently the picture are 'stocked' at the root level (same level than the file manage.py the question is why? and how can I change it and what is the best way to do so?

alix is right that "You need to specify where to store images uploaded by user" by specifying upload_to in the field constructor. But you don't need a special class to handle all of this. Way too complicated. Let's say you have this in your settings:
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
MEDIA_URL = '/uploads/'
In your template, you should now be able to do something like:
<img src="{{ post.image.url }}">

You need to specify where to store images uploaded by user. Try this in your models.py:
from django.utils.deconstruct import deconstructible
#deconstructible
class PathAndRename(object):
def __init__(self, sub_path):
self.path = sub_path
def __call__(self, instance, filename):
ext = filename.split('.')[-1]
# set filename as random string. change here as you want
filename = '{}.{}'.format(uuid4().hex, ext)
# return file path
return os.path.join(self.path, filename)
path_and_rename = PathAndRename("/images")
And then in model:
image = models.ImageField(upload_to=path_and_rename)
You can read more about ImageField here and here

Related

In views.py file ==> category_posts = Post.object.filter(category=cat) returns an empty query set. The 'Post' model has sample posts with categories

I am creating a blog application in django where i encountered this unusual issue. I am not being able to filter and display blog posts category wise. Please find my code below. Thanks in advance. I have spent two full days trying to figure this out and still
got nothing.
MODELS.py
This is the model which i have created for a blog post.
class Post(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
post_date = models.DateField(auto_now_add=True)
category = models.CharField(max_length=255, default="uncategorized")
def __str__(self):
return self.title + ' | ' + str(self.author)
def get_absolute_url(self):
#return reverse('article-detail', args=(str(self.id)))
return reverse('homepage')
VIEWS.py
This is the view that i have created for a category wise blog posts.
def CategoryView(request,cat):
category_posts = Post.objects.filter(category=cat)
return render(request,'categories.html',{'category_posts':category_posts})
URLS.py
The urls.py file.
path('category/<str:cat>/', CategoryView, name = 'category'),
CATEGORIES.html
This will be the final display page where the category_posts is displayed as an empty queryset. The for loop is unable to run because category_posts is an empty queryset. Single word categories are also empty(to rule out a slugify issue)
{% extends 'base.html' %}
{% load static %}
{% block content %}
<ul>
{% for post in category_posts %}
<li>
<div class="category">
{{ post.category }}
</div>
<a href="{% url 'article-detail' post.pk %}">
<h3><b>{{ post.title }} </b></h3>
<p class=card-date>
<big>{{ post.author }}</big>
<small>-{{ post.post_date }}</small>
</p>
<p class="excerpt-text">{{ post.body | slice:"100" |safe}}</p>
<div class="article-thumbnail">
<img src="{% static "images/bg.png" %}" alt="article-thumbnail" >
</div>
<div class="overlay">
</a>
</li>
{% endfor %}
{% endblock %}

How Do I Get Django to Show Image Field From Model in Templates?

I am trying to get the uploaded image to show in the project template. Here is what my code looks like currently:
projects.html
{% extends "base.html" %}
{% block content %}
<h1>{{ project.title }} HELLO</h1>
<div class="content-section">
<div class="media">
<img src="{{ project.image.url }}" alt="beach" width=250px height=250px />
</div>
<div>
<h5>About the project:</h5>
<p>{{ project.description }}</p>
<br>
<h5>Technology used:</h5>
<p>{{ project.tools }}</p>
</div>
</div>
{% endblock content %}
models.py
class Project(models.Model):
title = models.CharField(max_length=500, unique=True)
description = models.TextField(max_length=500)
tools = models.CharField(max_length=200)
image = models.ImageField(default='default.jpg', upload_to="beach_photos", blank=True)
def __str__(self):
return f'{self.title}'
views.py
from django.shortcuts import render
from django.http import HttpResponse
from projects.models import Project
def projects(request):
project = {
'project':Project.objects.all()
}
return render(request, 'projects/projects.html', context = project)
settings.py configuration (app is installed)
STATIC_URL = 'static/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
When I inspect the image element in the webpage, the source shows up as
src=""
None of the other calls to the model are appearing either.
Any help would be appreciated.
i think you forgot to add a for-loop in your template. try this:
{% for p in project %}
{{ p.title %}}
{% endfor %}
Make sure that the image field of your record in the database is full.
Access the required model with the python manage.py shell command and check if this model has a value of variable.image.url.

Load an image from aws s3 bucket to django application

I made a django app that stores notes of different semesters and branches and I want to display the profile image of the uploader of the post right next to their name in homepage of my website. I am using my staticfiles directly from the S3 bucket
The notes that the users upload is stored in the notes/models.py whereas the user's profile and their profile image is stored in users/models.py
What I want to do is in home.html (below) use something like,
{% static post.uploader.profile.image.url %} but suddenly it does not work.
Settings.py
AWS_ACCESS_KEY_ID='XXXXXXXXXXXXXXXXXX'
AWS_SECRET_ACCESS_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
AWS_STORAGE_BUCKET_NAME='django-XXXXX'
AWS_S3_REGION_NAME = "ap-south-1"
AWS_S3_SIGNATURE_VERSION = "s3v4"
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
# s3 static settings
AWS_LOCATION = 'staticfiles'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_LOCATION}/'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
# s3 public media settings
PUBLIC_MEDIA_LOCATION = 'media'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_MEDIA_LOCATION}/'
DEFAULT_FILE_STORAGE = 'django_project.storage_backends.PublicMediaStorage'
# s3 private media settings
PRIVATE_MEDIA_LOCATION = 'private'
PRIVATE_FILE_STORAGE = 'django_project.storage_backends.PrivateMediaStorage'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
notes/models.py
class Notes_Model(models.Model):
"""Store notes of different branches and semesters."""
uploader = models.CharField(max_length=200)
title = models.CharField(max_length=200)
date_posted = models.DateTimeField(auto_now_add=True)
description = models.TextField(max_length=2500)
branch_choice = models.CharField(max_length=50, choices=branch_choices, default='cse')
file_semester = models.IntegerField(choices=semester_choice)
file = models.FileField()
syllabus = models.TextField(max_length=200, default='No Syllabus Availibe Yet')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("notes-detail", kwargs={"pk": self.pk})
users/models.py
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.svg', upload_to='profile-pics')
def __str__(self):
return (f'{self.user.username} Profile')
def save(self):
super.save()
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
home.html
{% extends "base.html" %}
{% block content %}
{% load static %}
<div>
{% for post in posts %}
<article class="media content-section">
<img class="rounded-circle article-img" <!--this src is posing the issue -->src="{% static post.uploader.profile.image.url %}" width="60" height="60" style="margin-right: 30px">
<div class="media-body">
<p class="mr-2 text-capitalize">{{ post.uploader }}</p>
<small class="text-muted font-italic">{{ post.date_posted }}</small>
<div class="article-metadata">
</div>
<h2><a class="article-title text-info text-capitalize" href="{% url 'notes-detail' post.id %}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content }}</p>
</div>
</article>
{% endfor %}
</div>
xml from aws s3 bucket says that no key is present but it is present in the bucket.
<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Key>staticfiles/</Key>
<RequestId>960CD372E7128E16</RequestId>
<HostId>
90tvY+TT6FkefEheQXtuOLv5T8fCvJsDzIOBpam8inz4GGdhpb9QXrkToDCl/3yN+69tJoUUYQo=
</HostId>
</Error>
Url that gets returned is: https://django-xxxxxxx.s3.amazonaws.com/staticfiles/
whereas it should be
Expected url that gets returned: https://django-xxxxxx.s3.amazonaws.com/staticfiles/profile.jpg
Problem:
Top left part of the image is not being rendered
You're using the {% static %} templatetag, for something that is not a static file. It's a media file. The value of post.uploader.profile.image.url should be the actual URL to the image as a media asset. Passing that URL to {% static %} tries looking up the URL as the name of a static asset, which is why you get the NoSuchKey error.

Django: blog image not uploading properly

I'm sure i'm obviouly did something very stupid but, when I try to upload my profile picture on my blog website, even when I add one through admin page, the picture doesn't come up..
so here's what's happening,
blog pic:
the picture right next to Kimmc6008, I should see my image, but somehow failed..
here's the code, I will upload more if needed.
models.py
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField()
def __str__(self):
return self.user.username
class CategoryBlog(models.Model):
title = models.CharField(max_length=20)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
comment_count = models.IntegerField(default=0)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(CategoryBlog)
featured = models.BooleanField(null=True)
def __str__(self):
return self.title
views.py
def blog(request):
post_list = Post.objects.all()
context = {
'post_list': post_list
}
return render(request, 'blog.html', context)
and my html
<!-- post -->
{% for post in post_list %}
<div class="post col-xl-6">
<div class="post-thumbnail"><img src="{{post.thumbnail.url}}" alt="..." class="img-fluid"></div>
<div class="post-details">
<div class="post-meta d-flex justify-content-between">
<div class="date meta-last">20 May | 2016</div>
{% for cat in post.categories.all %}
<div class="category">{{ cat }}</div>
{% endfor %}
</div><a href="/post">
<h3 class="h4">{{ post.title }}</h3></a>
<p class="text-muted">{{ post.overview }}</p>
<footer class="post-footer d-flex align-items-center">
<a href="#" class="author d-flex align-items-center flex-wrap">
<div class="avatar"><img src="{{ post.author.profile_picture.url }}" alt="..." class="img-fluid"></div>
<div class="title"><span>{{ post.author.user.username }}</span></div>
</a>
<div class="date"><i class="icon-clock"></i>{{ post.timestamp|timesince }} ago</div>
<div class="comments meta-last"><i class="icon-comment"></i>{{ post.comment_count }}</div>
</footer>
</div>
</div>
{% endfor %}
Thank you for your help!!
EDIT
I noticed I was missing MEDIA_ROOT in my settings.py.
Would this be the reason why?
Add the upload_to argument in your ImageField
profile_picture = models.ImageField(upload_to='pictures')
And these are the basic settings you need to have in your django project for image/files handling
project/urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [..]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Python/Django - Get value of a ManyToManyField in a for tag

I can't get the image related value when I'm using {% for %} with the class Article. I tried with select_related, but I don't know how to define image to be correctly in displayed in the src="" attribute of my <img /> tag
Is there a clean way to make appear as I want?
models.py
class Image(models.Model):
gallery = models.ManyToManyField(Gallery)
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='static/images/gallery')
def __str__(self):
return self.name
class Article(models.Model):
section = models.ForeignKey(Menu)
title = models.CharField(max_length=100)
text = models.TextField()
type = models.ForeignKey(Type)
image = models.ManyToManyField(Image)
def __str__(self):
return self.title
views.py
def index(request):
slider = Article.objects.all()
images = Image.objects.all()
return render(request, 'cms/index.html', locals())
template
{% for i in slider %}
<li>
<img src="{{i.image}}" alt="{{i.title}}"/>
<h2>{{i.title}}</h2>
<p>{{i.text}}, {{i.image_url}}</p>
</li>
{% endfor %}
You have to use 2 forloop for displaying images in manytomany table.
{% for i in slider %}
<li>
{% for im in i.image.all %}
<img src="{{im.image.url}}" alt="{{im.name}}"/>
{% endfor %}
<h2>{{i.title}}</h2>
<p>{{i.text}}, {{i.image_url}}</p>
</li>
{% endfor %}
Article.image is a ManyToMany field. Which image You want to display? First?
<img src="{{i.image.all.0.image.url}}" alt="{{i.title}}"/>
All?
{% for im in i.image.all %}
<img src="{{im.image.url}}" alt="{{im.name}}"/>
{% endfor %}

Categories

Resources