Load an image from aws s3 bucket to django application - python

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.

Related

How can I acces to my AWS S3 bucket in django?

I am working for the first time with aws s3, where I have images to upload from the django admin, everything works perfect on localhost, but once deployed the images are uploaded but not displayed on the web
settings.py
AWS_ACCESS_KEY_ID = 'my acceskey'
AWS_SECRET_ACCESS_KEY = 'my secret key'
AWS_STORAGE_BUCKET_NAME = 'mybucketname'
AWS_DEFAULT_ACL = None
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
STATIC_LOCATION = 'static'
PUBLIC_MEDIA_LOCATION = 'media'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_MEDIA_LOCATION}/'
DEFAULT_FILE_STORAGE = 'portfolio.storages.MediaStore'
models.py
class Project(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=200)
link = models.CharField(max_length=250)
another_link= models.CharField(max_length=250, null= True, blank=True)
image = models.ImageField(upload_to='media/')
views.py
def project(request):
projects = Project.objects.all().order_by('-id').values()
return render(request, "works.html", {"projects": projects})
Template file
{% for project in projects %}
{% csrf_token %}
<div class="row">
<div class="col-md-12 col-md-offset-1">
<div class="row">
<div class="col-xs-12 col-md-6">
<h3>{{project.name}}</h3>
<p style=> {{project.description}} </p>
Source Code
See Live
</div>
<div class="col-xs-6 col-md-4">
<img src="{{project.image.url}}" width="360" height="200" >
</div>
</div>
</div>
</div>
{% endfor %}
In the Html not return a asw link, return this
<img src="" width="360" height="200">
Images are loaded perfectly in the S3 bucket but are not displayed in the HTML.

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.

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')

image is not showing in django templates am new in django and working on a project...i idid lots of rid of this error but nothing happen

am trying to show pic in django tempate but its not working
here is my settings.py where the path of static and media file
STATIC_URL = '/static/'
STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'),
]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR , "media")
this is my model.py
the image is store under static/img folder
class Loader_post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="Loader")
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False, blank=False, unique=True)
receiver_name = models.CharField(max_length=150)
sending_item = models.CharField(max_length=150)
image_of_load = models.ImageField(default='',upload_to='static/img')
weight = models.CharField(max_length=150)
metric_unit = models.CharField(max_length=30, default='')
quantity = models.PositiveIntegerField()
pick_up_time = models.DateField()
drop_time = models.DateField()
paid_by = models.CharField(max_length=150)
created_at = models.DateTimeField(auto_now=True)
published_date = models.DateField(blank=True, null=True)
this is my html template for showing user posted data
{% extends "post.html" %}
{% block content %}
{% load static %}
{% for loader in Loader %}
<h4>Loader Id- {{loader.id}}</h4> Username-{{user.username}}
<h3>Sender name-{{loader.sender_name}}</h3>
</h4>
<p class="card-text">
<h4>pick up station-{{loader.pick_up_station}}</h4>
</p>
<img src="{{ loader.image.url }}" alt="image">
<p class="card-text">{{loader.destination_station}}</p>
<p class="card-text">{{loader.phone_number}}</p>
<p class="card-text">{{loader.receiver_name}}</p>
<p class="card-text">{{loader.sending_item}}</p>
<p class="card-text">{{loader.weight}}</p>
<p class="card-text">{{loader.quantity}}</p>
<p class="card-text">{{loader.pick_up_time}}</p>
<p class="card-text">{{loader.drop_time}}</p>
<p class="card-text">{{loader.paid_by}}</p>
<p class="card-text">{{loader.created_at}}</p>
<a class="btn btn-primary" href="{% url 'Loader:Delete' loader.id %} ">delete</a>
<a class="btn btn-primary" href="{% url 'Loader:Update' loader.id %} ">update</a>
</div> {% endfor %} {% endblock content %}
this is my urls.py
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static
app_name = 'Loader'
urlpatterns = [
path('post_detail/', views.Loader_post_view.as_view(), name="post_detail"),
path('post/', views.post.as_view(), name="post"),
path('my_job/', views.Loader_post_list.as_view(), name="my_job"),
path('delete/<int:pk>', views.Loader_post_delete.as_view(), name="Delete"),
path('update/<int:pk>', views.Loader_post_update.as_view(template_name="post_detail.html"), name="Update")
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
how can i remove this error or any bug in my code?
Take a closer look
First of all, you use different names. In the models.py the image attribute corresponds to image_of_load, whereas in your template the src is equal to {{loader.image.url}} not {{loader.image_of_load.url}}. Second, try to put {% load static %} at the very top of your file, which is an advice from the documentation, at least above the {% block content %} tag.
I think that on the models.py file, you should use upload_to='img' because you have set your static folder directory. Remember that the uploaded images by users go to your media folder / URL, not your static folder. The static folder is for CSS files and images that you serve, such as your website's logo.
I hope that helps. Feel free to ask me any more questions!

Upload an image and display it on a webpage with Django

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

Categories

Resources