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