Rendering blank ImageFields in Django template - python

I am trying to render an instance of this model in my template:
class Candidate(models.Model):
UserID = models.ForeignKey(User, on_delete=models.CASCADE)
ElectionID = models.ForeignKey(Election, on_delete=models.CASCADE)
Bio = models.CharField(max_length=500, blank=True)
Poster = models.ImageField(upload_to="profilepics/", null=True, blank=True)
I am having trouble with rendering the Poster attribute which, as you can see, has the option of being blank.
When I try to render the following html in the template:
<h1>{{candidate.UserID.first_name}} {{candidate.UserID.last_name}} ({{candidate.UserID.username}})</h1>
<h2>{{candidate.ElectionID}}</h2>
<img src="{{candidate.Poster.url}}" width=240><br>
I get an error if Poster is blank.
ValueError: The 'Poster' attribute has no file associated with it.
How do I prevent this error? I want to show nothing if Poster is blank and obviously show the image if it isn't.

Use an if condition.
<h1>{{candidate.UserID.first_name}} {{candidate.UserID.last_name}} ({{candidate.UserID.username}})</h1>
<h2>{{candidate.ElectionID}}</h2>
{% if candidate.Poster %}
<img src="{{candidate.Poster.url}}" width=240>
{% endif %}
<br>

Related

Using HTMX, hx-push-url

just looking for some detailed pointers on how to hx-push-url as I have come across some problems and looking for some direction. I am a relative beginner at Django and just started using HTMX.
The aim. I'm building a simple image gallery and have a grid of thumbnails, I am using HTMX to load the list of images within that gallery when a uses click a thumbnail.
This works well, I am using Django-HTMX and a if conditional in the View to deal with the HTMX request which serves the partial HTML into the thumbnail page.
The problem was that my URL did not change. My thumbnail is http://127.0.0.1:8000/gallery/ and when I click on a gallery to view images within, the url remains the same, so, I used htmx-push-url so that URL would appear something like http://127.0.0.1:8000/gallery/news. This works and the URL changes.
Anyway, onward.
I have a button on my images list page that take you back to the thumbnail page, but when using this I get a 404 error, and also when I refresh my image list page I get a 404. Obviously there is no URL and view for http://127.0.0.1:8000/gallery/news. I Just have little idea how to solve this.
When I look in the console I get a HTMX-target error when clicked the back button, and nothing happens. And, as I say, a refresh gets a 404.
Code below should explain things better.
Models
name = models.CharField(max_length=200, null=True)
description = models.CharField(max_length=200, null=True, blank=True,
help_text="Gallery description on gallery page")
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")
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)
URLS (relevant)
path("gallery/", views.GalleryView, name="gallery"),
Views
def GalleryView(request):
if request.htmx:
slug = request.GET.get('slug')
pics = get_object_or_404(Albums, slug=slug)
context = {'pictures': Media.objects.filter(album_pictures=pics),
'description': Albums.objects.filter(slug=slug)}
return render(request, 'main/gallery-detail.html', context=context)
context = {'objects_list': Albums.objects.all()}
return render(request, 'main/gallery.html', context=context)
Gallery HTML {relevant code)
<div class="gallery-body">
{% for img in objects_list %}
<div class="item col-xs-6 col-sm-6 col-md-4">
<figure class="overlay"> <a hx-post="{{ request.path }}?slug={{ img.slug }}"
hx-target=".gallery-body"
hx-swap="outerHTML"
hx-push-url="/gallery/{{ img.slug }}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
{% endfor %}
The partial that gets called showing the images within the galleries.
<button class="btn btn-primary"
hx-get="{% url 'main:gallery' %}"
hx-target=".gallery-body"
hx-push-url="/gallery"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
<h6>Back to Gallery page</h6></button></div>

Django - show all images assigned to the post

I am creating blog application and I would like to show all images which were uploaded to the single blog post.
Here are my Models.py:
class Post(models.Model):
title = models.CharField(max_length=100)
content = RichTextField(blank=True, null=True)
class PostImage(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE, related_name='postimages')
image = models.ImageField(upload_to='gallery/')
Views.py
class PostGalleryView(DetailView):
model = Post
template_name = 'blog/gallery.html'
context_object_name = 'photos'
In the template if I put there {{ photos.postimages }} then it shows on the page: blog.PostImage.None
even though that 2 images are uploaded to the particular blog post. {{ photos.postimages.count }} shows number 2. If I tried to loop through photos.postimages it throws an error: 'RelatedManager' object is not iterable. Any idea how I can access the PostImage model in the template?
Try using loop in your template with all like:
{% for photo in photos.postimages.all %}
{{ photo.image }}
{% endfor %}

Python / Django / Jinja2: How to extend a variable name with the value of another variable (e.g. in a for-loop)?

In my django db model I have e.g. 5x ImageField, which I want to use for a carousel in the front end:
slider_image_1 = models.ImageField(upload_to='images/', blank=True)
slider_image_2 = models.ImageField(upload_to='images/', blank=True)
slider_image_3 = models.ImageField(upload_to='images/', blank=True)
slider_image_4 = models.ImageField(upload_to='images/', blank=True)
slider_image_5 = models.ImageField(upload_to='images/', blank=True)
Depending whether the images were uploaded or not, I want to display the images and I am looking for an approach similar to something like this:
{% for FOO in range(5) %}
{% if object.slider_image_|extend_name_with:FOO %}
<img src="{{ object.slider_image_|extend_name_with:FOO.url }}">
{% endif %}
{% endfor %}
Is something similar possible? What are other good approaches for this problem?
The recommended approach for complex logic in templates is to write the logic in a model method, rather than in the template itself.
In your case, I think this is what you want:
class SomeModel(models.Model):
slider_image_1 = models.ImageField(upload_to='images/', blank=True)
slider_image_2 = models.ImageField(upload_to='images/', blank=True)
slider_image_3 = models.ImageField(upload_to='images/', blank=True)
slider_image_4 = models.ImageField(upload_to='images/', blank=True)
slider_image_5 = models.ImageField(upload_to='images/', blank=True)
#property
def slider_images(self):
fields = [field.name for field in self._meta.get_fields()]
results = []
for field in fields:
if 'slider_image' in field:
data = getattr(self, field)
if data:
results.append(data.url)
return results
#property
def slider_images(self): # simplified version
results = [getattr(self, field.name) for field in self._meta.get_fields()
if 'slider_image' in field]
return [result.url for result in results if result]
Now you can easily access this list in your templates:
{% for url in object.slider_images %}
<img src="{{ url }}">
{% endfor %}
This is a bit out of scope for this question, but your slider_image fields looks like it should be a single ManyToManyField. Using a M2M here would massively simplify the amount of work you are doing, and would eliminate the need for my solution entirely. I can't really give you a solution using this because you will probably need to change several pieces of logic throughout your code before this will work.

Check if a user has voted on a Post, in the template

Here's my Post model:
models
class Post(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
title = models.TextField(max_length=76)
content = models.TextField(null=True, blank=True)
...
class PostScore(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
post = models.ForeignKey(Post, related_name='score')
upvotes = models.IntegerField(default=0)
downvotes = models.IntegerField(default=0)
And here's my template. I want to do something like this... if the user has upvoted or downvoted the Post, then hide the upvote/downvote buttons:
{% if request.user in Post.has_answered %}
{% else %}
<img src="upvote.png" class="upvote" />
<img src="downvote.png" class="downvote" />
{% endif %}
I planned to do this by adding a ManyToManyField called has_answered to my Post model, but i'm unable to do that as I get this error:
post.Post.has_answered: (fields.E304) Reverse accessor for 'Post.has_answered' clashes with reverse accessor for 'Post.user'.
HINT: Add or change a related_name argument to the definition for 'Post.has_answered' or 'Post.user'.
post.Post.user: (fields.E304) Reverse accessor for 'Post.user' clashes with reverse accessor for 'Post.has_answered'.
HINT: Add or change a related_name argument to the definition for 'Post.user' or 'Post.has_answered'.
Any idea how I can fix this? I'm not too sure about the error message as I don't think I can alter my current user field.
You can change your models to like this. You might not need PostScore model.
class Post(models.Model):
# Other Fields i.e title, content, author ...
upvotes = models.ManyToMany(User)
downvotes = models.ManyToMany(User)
You can get upvotes on a Post using this.
upvotes = post_object.upvotes.count()
downvotes = post_object.downvotes.count()
To see whether user has upvoted or not,
if request.user in post_object.upvotes.all():
# This user has upvoted this post
Same for downvotes.
You can do similar thing in your template as well and hide/show buttons based on condition.
{% if request.user in post_object.upvotes.all %}
<!-- show upvote button highlighted -->
{% elif request.user in post_object.downvotes.all %}
<!-- show downvote button highlighted -->
{% else %}
<!-- Show both buttons (not highlighted) -->
{% endif %}
Hope this helps.
Have you tried send the flag from your django views to template like :
def myView(request):
parameters['is_user_voted'] = PostScore.objects.filter(user=self.request.user).exists()
.....
.....
send ```parameters``` to your template using render()
And change you template as:
{% if is_user_voted == 'True' %}
{% else %}
<img src="upvote.png" class="upvote" />
<img src="downvote.png" class="downvote" />
{% endif %}

Show images on Django Non Rel Templates using Google App Engine

I'm doing an app with Django Non Rel on GAE, and i want to show the Profile Image of the user in the template but i can't here is the model:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class userProfile(models.Model):
def url(self, filename):
url = "MultimediaData/Users/%s/%s"%(self.user.username, filename)
return url
user = models.OneToOneField(User)
email_public_user = models.EmailField(blank=True, null=True)
url_user = models.CharField(max_length=200, blank=True, null=True)
company_user = models.CharField(max_length=200, blank=True, null=True)
position_user = models.CharField(max_length=200, blank=True, null=True)
photo_user = models.ImageField(upload_to=url)
def __unicode__(self):
return self.user.username
For now i'm adding the photo via admin to see if i can show the image, here is the template
<div class="navbar-header nav-img">
{% if user.get_profile.photo_user %}
<img class="navbar-brand" src="{{user.get_profile.photo_user}}">
<p class="navbar-brand">{{user.get_username}}</p>
{% else %}
<img class="navbar-brand" src="/media/img/principal_html/img1.png">
<p class="navbar-brand">{{user.get_username}}</p>
{% endif %}
It shows the username, but not the image, i put the user.get_profile.photo_user in a and i got this
ahRkZXZ-c29mdHN5c3RlbWFuYWdlcnIiCxIVX19CbG9iVXBsb2FkU2Vzc2lvbl9fGICAgICAzKYKDA/MultimediaData/Users/[username]/img.jpg
There's no view yet because im uploading the image using the django admin and when i save the user with his photo shows the same url
How can i solve this? I need to show the image...plz help

Categories

Resources