Flask: Can't display an uploaded image - html

I am working on a small blogging page using Flask. I set up an admin page where I can create articles(using wtforms) that I want to be displayed on the (front end) homepage. All my form fields in the Create Article Form(in my Admin page) are saving their respective inputs(Title, Image, PreviewText, Content, Category). When I click on post article it is succesfully put into the sqlite db and everything except the uploaded image is displayed on the homepage. In my CreateArticleForm I am using the enctype="multipart/form-data"
Here is my routes.py. As you can see I set up an save image function above the route(to save the upladed image into my static/images/article_imgs folder and included it into the route. After uploading the image and checking the folder I can see the image was added to that folder.
def save_article_image(form_picture):
random_hex = secrets.token_hex(8)
_, f_ext = os.path.splitext(form_picture.filename)
picture_fn = random_hex + f_ext
picture_path = os.path.join(app.root_path, 'static/images/article_imgs', picture_fn)
form_picture.save(picture_path)
return picture_fn
######################admin-Routes
# create article
#app.route('/createarticle', methods=['GET', 'POST'])
#login_required
def create_article():
form = CreateArticleForm()
if form.validate_on_submit():
if form.picture.data:
picture_file = save_article_image(form.picture.data)
article_image=picture_file
article = Article(title=form.title.data, article_image=picture_file,
article_preview=form.preview.data, article_content=form.content.data,
category=form.category.data, author=current_user)
db.session.add(article)
db.session.commit()
flash('Article was posted.', 'success')
return render_template('admin/createarticle.html', form=form)
Here is my home route, where the article I create is displayed:
#app.route('/')
def home():
article = Article.query.all()
return render_template('home.html', article=article)
Finally my home.html, where the data is put into html. Here you can see the img-Tag where I am trying to get the uploaded image to be displayed.
{% for article in article %}
<div class="col-xs1-12 col-sm-6 col-md-4">
<div class="card mt-3">
<img class="card-img-top" src="{{ url_for('static', filename='article.article_image') }}"
alt=" Card image cap">
<div class="card-body">
<h6 class="card-category">{{ article.category }}</h6>
<h5 class=" card-title">{{ article.title }}</h5>
<p class="card-text">{{ article.article_preview }}</p>
<p class="text-right">{{ article.date_posted.strftime('%d.%m.%Y') }}</p>
Read More
</div>
</div>
</div>
{% endfor %}
All I get is an error message in the console: Failed to load resource: the server responded with a status of 404 (NOT FOUND). Again I can see the article with the title, preview text etc. but the article_image.

It says line 59, which is the img Tag where I want to display the image. Filename = to the picture_file I saved the image.
{% for article in article %}
<div class="col-xs1-12 col-sm-6 col-md-4">
<div class="card mt-3">
<img class="card-img-top" src="{{ url_for('static', filename=picture_file) }}" alt=" Card image cap">
<div class="card-body">
<h6 class="card-category">{{ article.category }}</h6>
<h5 class=" card-title">{{ article.title }}</h5>
<p class="card-text">{{ article.article_preview }}</p>
<p class="text-right">{{ article.date_posted.strftime('%d.%m.%Y') }}</p>
Read More
</div>
</div>
</div>
{% endfor %}

I just changed the src of the img tag to filename=form.picture.data since I want the data that I put into the form. Thus, I get an jinja error saying:
jinja2.exceptions.UndefinedError: 'form' is undefined and it points me to my home route saying:
return render_template('home.html', article=article)
and my home.html saying
<img class="card-img-top" src="{{ url_for('static', filename=form.picture.data) }}" alt=" Card image cap">
{% for article in article %}
<div class="col-xs1-12 col-sm-6 col-md-4">
<div class="card mt-3">
<img class="card-img-top" src="{{ url_for('static', filename=form.picture.data) }}" alt=" Card image cap">
<div class="card-body">
<h6 class="card-category">{{ article.category }}</h6>
<h5 class=" card-title">{{ article.title }}</h5>
<p class="card-text">{{ article.article_preview }}</p>
<p class="text-right">{{ article.date_posted.strftime('%d.%m.%Y') }}</p>
Read More
</div>
</div>
</div>
{% endfor %}
The way I understand it, is that my home route does not know the picture data so I try to put define the argument inside my home route with filename=picture_file and then the error says
NameError
NameError: name 'picture_file' is not defined
#app.route('/')
def home():
article = Article.query.all()
return render_template('home.html', article=article, filename=picture_file)

Related

Boostrap Modal and loading images in Django

Firstly I am a beginner at Django but am slowly learning, I have deployed a couple of Django projects, but I have come up against a problem where I have run out of ideas on how to solve due to a lack of knowledge. I have no experience really with the frontend, I have yet to touch Boostrap (although obviously know some HTML ) or JS in detail.
I am using a HTML template to build a Photography portfolio, I have a Album view with image thumbnails which work nicely and I have a href to the list of images within that Album.
The problem is that template uses Boostrap Modal to open the list of images within the same page, this looks very nice and I want to try and keep it working but unsure how to pass my Django data (ie., the slug from the href ) through the modal.
What I have attempted is to split my gallery-detail template which takes in the listview of the Album images filter by that album, and then include that within my main Gallery template which uses my Gallery ListView to show the thumbnails. I though the modal would work this way as they would maybe technically be on the same page?
I'm just unsure, how do I pass view context into modals? Below is my relevant code which hopefully makes it easier to understand what I am trying to do
Where I am at the moment....the modal loads on same page, but no images are shown just the close X icon. If I right-click and open the URL all images open corresponding to that Album correctly but with no css or styling.
Models
name = models.CharField(max_length=200, null=True)
slug = AutoSlugField(populate_from='name')
created = models.DateTimeField()
visable = models.BooleanField(default=False)
type = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
image = models.ForeignKey('Media', on_delete=models.CASCADE)
album_images = models.ManyToManyField('Media', related_name="album_pictures")
def __str__(self):
return str(self.name)
class Media(models.Model):
timestamp = models.DateTimeField()
image = models.ImageField(upload_to="media")
order = models.IntegerField(default=0)
visable = models.BooleanField(default=True)
categories = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
verbose_name_plural = "Media"
Views. Straightforward enough.
class GalleryView(ListView):
template_name = "main/gallery.html"
model = Albums
class GalleryDetailView(ListView):
template_name = "main/gallery-detail.html"
model = Media
def get_queryset(self):
gallery = get_object_or_404(Albums, slug=self.kwargs['slug'])
print(gallery)
return Media.objects.filter(album_pictures=gallery)
Templates. Gallery.
{% extends "main/base.html" %}
{% load static %}
{% block gallery %}
{% for gallery in object_list %}
<div class="item col-xs-6 col-sm-6 col-md-4">
<figure class="overlay"> <a href="{% url 'main:gallery_detail' gallery.slug %}" data-toggle="modal" data-target="#myModal1">
<div class="text-overlay caption">
<div class="info">
<h2 class="post-title">{{ gallery.name }}</h2>
<div class="meta"> <span class="count">7 Photos</span> <span class="category">Hobby</span></div>
</div>
</div>
<img src="{{ gallery.image.image.url }}" alt="" /></a> </figure>
</div>
{% endfor %}
{% include "main/gallery-detail.html" %}
{% endblock %}
gallery-detail template
{% extends "main/base.html" %}
{% load static %}
{% block gallery %}
{% for gallery in object_list %}
<div class="item col-xs-6 col-sm-6 col-md-4">
<figure class="overlay"> <a href="{% url 'main:gallery_detail' gallery.slug %}" data-toggle="modal" data-target="#myModal1">
<div class="text-overlay caption">
<div class="info">
<h2 class="post-title">{{ gallery.name }}</h2>
<div class="meta"> <span class="count">7 Photos</span> <span class="category">Hobby</span></div>
</div>
</div>
<img src="{{ gallery.image.image.url }}" alt="" /></a> </figure>
</div>
{% endfor %}
{% include "main/gallery-detail.html" %}
{% endblock %}

Django views opens different content

I am new to Django. I have created 2 seperate views and URLs, however, when I load my development server and click on slides to open slides_detail.html, it opens sub_detail.html, at this point I have no clue what could cause that as there are no similar names which would lead to opening completely different detail page. Both slides and subcontent sits in the same HTML document, same with URLs and views. There are no errors, to show. Thanks in advance:
URLS:
path('<int:sub_id>/', views.sub_detail, name='sub_detail'),
path('<int:slides_id>/', views.slides_detail, name='slides_detail'),
Views:
# Will show specific sub content details
def sub_detail(request, sub_id):
subcontent = get_object_or_404(SubContent, pk=sub_id)
context = {
'subcontent': subcontent,
}
return render(request, 'home/sub_detail.html', context)
# Will show specific slides content details
def slides_detail(request, slides_id):
slides = Slides.objects.get(pk=slides_id)
context = {
'slides': slides,
}
return render(request, 'home/slides_detail.html', context)
HTML for slides:
{% for slides in slides %}
<div class="swiper-slide">
<div class="card">
<a href="{% url 'slides_detail' slides.id %}">
<img src="{{ slides.image.url }}" class="card-img-top img-height" alt="..."></a>
<div class="card-body bg-dark">
<h5 class="card-title text-light font-weight-bold text-center">{{ slides.title }}</h5>
</div>
</div>
</div>
{% endfor %}
HTML for subcontent:
{% for sub in subcontent %}
{% if forloop.counter|divisibleby:2 %}
<div class="row">
{% if sub.image %}
<div class="col-md-6 section-index-img">
<img src="{{ sub.image.url }}" class="rounded img-fluid" alt=""/>
</div>
{% endif %}
<div class="col-md-6">
<a href="{% url 'sub_detail' sub.id %}">
<h4>{{ sub.title }}</h4>
</a>
<p class="text-muted">{{ sub.description | linebreaks }}</p>
</div>
</div>
{% else %}
I have created 2 seperate views and URLs, however, when I load my development server and click on slides to open slides_detail.html, it opens sub_detail.html.
You did not create two separate URLs, you created the same path. Both paths will fire on the same patterns. This thus means that if you have a {% url 'slides_detail' 42 %}, for example, it will be written as /42, but this is also a valid path for the sub_detail, so when you make a request with that path, Django will "fire" the first view that matches, in this case sub_detail.
You should make the paths non-overlapping, for example:
path('sub/<int:sub_id>/', views.sub_detail, name='sub_detail'),
path('slide/<int:slides_id>/', views.slides_detail, name='slides_detail'),

How can I attached title, content and date on the template

As for now I am following a video to create a blog with django. But, I have problem attaching the title, content, author and date on the template which I had downloaded from colorlib. I used the method below in the index.html file but they do now show:
{% extends 'base.html' %}
{% load static %}
{% block content %}
{% for post in object_list %}
<div class="site-section">
<div class="container">
<div class="row">
<div class="col-lg-8">
<div class="row">
<div class="col-12">
<div class="section-title">
<h2>Editor's Pick</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="post-entry-1">
<img src="{% static 'images/img_h_1.jpg' %}" alt="Image" class="img-fluid">
<h2></h2>
<p>{{ obj.overview }}</p>
<div class="post-meta">
<span class="d-block">
{{ obj.author.user.username }} in {{ cat }}</span>
<span class="date-read">{{ obj.timestamp|timesince }} ago<span class="mx-1">&bullet;</span> 3 min read <span class="icon-star2"></span></span>
</div>
</div>
</div>
{% endfor %}
Assuming object_list is the list of posts. You instantiated the loop variable as post. Therefore post is the variable representing a post instead of obj which you try to access. So replace everywhere you have obj with post or you can make the loop variable obj instead. Either way
Since you are iterating through each post from the list of posts, so to access the value of each post, you should use {{ post.title }} to show the title of the post, {{ post.author.username }} to show the username of the author of the post, and so on.

Display uploaded images in HTML - DJANGO

I am trying to display images that are upload by the user in my HTML.
I'd set the following:
Settings:
MEDIA_URL = '/media/'
MEDIAFILES_DIRS = []
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
Upload files within the model to directory:
class Artikel(models.Model):
artikel_pic = models.ImageField(upload_to='assortiment/images/', blank=True, verbose_name="Afbeelding")
urls:
urlpatterns = [
path(r'', include('main.urls')),
path(r'', include('assortiment.urls')),
path('admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Views.py:
class AssortimentView(TemplateView):
template_name = "assortiment/assortiment.html"
def get(self, request):
artikel = Artikel.objects.all()
context_artikel = { 'artikel': artikel}
return render (request, self.template_name, context_artikel)
url that is given when i open the image in the admin panel:
http://127.0.0.1:8000/media/assortiment/images/choco_ijs.jpg
It displays correctly over here.
html code that needs to diplay the image:
{% for art in artikel %}
<div class="col-sm-2">
<div class="card" >
<img class="card-img-top" src="{{MEDIA_URL}}/images{{ artikel_pic.url }}" alt="{{art.artikel_naam}}">
<div class="card-body">
<h5>{{ art.artikel_naam }}</h5>
<p class="card-text">{{ art.artikel_omschrijving }}</p>
</div>
<div class="row mr-auto">
<div class="col-8">
<button type="submit" href="#" class="btn btn-info" id="button-assortiment-info">info </button>
</div>
<div class="col-4">
<button type="submit" href="#" class="btn btn-primary" id="button-assortiment-add">+</button>
</div>
</div>
</div>
</div>
{% endfor %}
I get a not found (304) error:
"GET /media/assortiment/images/choco_ijs.jpg HTTP/1.1" 304
It looks like everything is going fine. Can't figure out what is going wrong though.
I tried to change the src within the html file to:
<img class="card-img-top" src="{{ artikel_pic }}" alt="{{art.artikel_naam}}">
<img class="card-img-top" src="{{ artikel_pic.url }}" alt="{{art.artikel_naam}}">
<img class="card-img-top" src="/images/{{ artikel_pic.url }}" alt="{{art.artikel_naam}}">
<img class="card-img-top" src="{{MEDIA_URL}}{{ artikel_pic.url }}" alt="{{art.artikel_naam}}">
It seems like the source is not routing to the right one.
Does anyone have some suggestions how to do this correctly?
add these lines in settings.py file
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media/')
and use this code in html file
<img class="card-img-top" src="{{ art.artikel_pic.url }}">

Objects all doesn't give ms anything inside the view method

I'm developing a new web app. I want to display data from the database to the html template. I don't get any errors but I don't get the data inside my views methode using 'Objects.all()'. When I tried the django shell it works.
I am using postgres database
enter image description here
#models.py
from django.db import models
from datetime import datetime
class Catégorie(models.Model):
désignation = models.CharField(max_length=200)
Description = models.TextField(blank=True)
Quantité_de_Stock = models.IntegerField()
photo_main = models.ImageField(upload_to='photos/%Y/%m/%d/')
est_publié = models.BooleanField(default=True)
date_de_modification = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.désignation
#views.py
from django.shortcuts import render
from .models import Catégorie
def index(request):
Catégorie_list=Catégorie.objects.all()
context = {
'Catégorie_list':Catégorie_list,
}
return render(request,'articles/Category.html',context)
#html
<div class="row">
{% if articles %}
{% for category in Catégorie_list %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card listing-preview">
<img class="card-img-top" src="{{ category.photo_main.url }}" alt="">
<div class="card-body">
<div class="listing-heading text-center">
<h4 class="text-primary" >{{ category.désignation }}</h4>
</div>
<hr>
Voir la catégorie
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="col-md-12">
<p>Aucune catégorie disponible</p>
</div>
{% endif %}
</div>
enter image description here
enter image description here