Django multiple images for post to render - html

For the past few days I have been trying to give access to the admin user to upload multiple images/slides for every single post, one idea I had in mind was nesting a for loop inside the posts for loop that for every post, render also every image associated with it but it seem's I cant get it quite right.
class Post(models.Model):
title = models.CharField(max_length = 128)
image = models.ImageField(default = 'default.jpg', upload_to = 'post_pics')
content = models.TextField()
date_posted = models.DateTimeField(default = timezone.now)
category = models.ForeignKey(Category, on_delete = models.CASCADE)
def __str__(self):
return f"{self.title} - {self.category}"
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default= None, on_delete = models.CASCADE, related_name= 'Images')
image = models.ImageField( upload_to = get_image_filename, verbose_name = 'Images')
def __str__(self):
return f"imazh per {self.post}"
and my Html:
<div class="post-list-container">
{% for post in posts %}
<article class="post-container">
<div class="post-top">
> Focus on the for loop here
{% for post.Images in post.Images %}
<img src="{{ post.Images.url }}">
{% endfor %}
<div class="post-title"><h1>{{ post.title }} </h1></div>
<div class="post-images">
<img class="rounded" src="{{ post.image.url }}">
</div>
</div>
<div class="post-middle">
<div class="post-content"><p> {{ post.content }}</p> </div>
</div>
<div class="post-bottom">
<div class="post-category"><h2>{{ post.category }}</h2>
</div>
<div class="post-date_posted"><h1>{{ post.date_posted|date:"F d, Y" }}</h1>
</div>
</div>
</article>
{% endfor %}
</div>
Is there any way to render those images this way?

A Post will have a related set, which is what you refer to that reverse relationship as.
By default, django will make the relationship on a Post instance images_set because it takes your model name on the relationship & adds _set.
You can also choose your own related name by setting the related_name attribute on the FK field. (docs)
Here's an example;
class Map(models.Model):
members = models.ManyToManyField(
User,
related_name='maps',
verbose_name=_('members')
)
# Reverse relationship:
User.maps.all()
Or in python using your models;
post = Post.objects.first()
print(f"Images in post {post.title}")
for image in post.images_set.all():
print(image.url)
So without a custom related_name, your template loop would be something like;
{% for image in post.images_set.all %}
<img src="{{ image.url }}">
{% empty %}
<p>No images found</p>
{% endfor %}

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 %}

Getting M2M field data in template Django

I want to get m2m data in my template through the views but failing to do so. The thing is that I'm able to show the data of m2m field looping it from template itself but it does slow down the website.
My Team apps Model looks like this:
class Team(models.Model):
title = models.CharField(max_length=255)
team_country = CountryField(max_length=200, blank=True, null=True)
members = models.ManyToManyField(User, related_name='teams')
created_by = models.ForeignKey(User, related_name='created_teams', on_delete=models.CASCADE)
Now in my tournament app I'm trying to get "members" of the team.
My Tournamet Views look like this:
def tournament_page(request, slug):
page = 'tournament_page'
user = request.user
tournament = Tournament.objects.get(slug=slug)
players = tournament.participants.select_related('user')
all_players = Profile.objects.select_related('user')
side_tourneys_ongoing = Tournament.objects.filter(state='Ongoing')[:10]
side_tourneys_upcoming = Tournament.objects.filter(state='Upcoming')[:10]
side_tourneys_completed = Tournament.objects.filter(state='Completed')[:10]
teams = Team.objects.select_related('created_by')
context = {
'page': page,
'tournament': tournament,
'side_tourneys_ongoing': side_tourneys_ongoing,
'side_tourneys_upcoming': side_tourneys_upcoming,
'side_tourneys_completed': side_tourneys_completed,
'teams': teams,
'players':players,
'all_players':all_players
}
Now I'm able to show the teams with their members in the template using for loop inside the template itself as:
Html template
<div class="grid-x">
{% for team in teams %}
{% for player in players %}
{% if team.id == player.active_team_id and team.game == tournament.game %}
<div class="wf-card event-team">
<div> {{team.title}} </div>
<div class="event-team-players">
{% for member in team.members.all %}
{{ member.username }}
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
What I want is to use this piece of code
{% for member in team.members.all %}
{{ member.username }}
{% endfor %}
in my views since it causes the website to slow down and idk why.
What I tried in my views is:
all_teams = Team.objects.all()
members = all_teams.members.all()
and
members = Team.objects.all().prefetch_related('members')
First one throws an error:
'QuerySet' object has no attribute 'members'
Second one shows lots of blank records
Tried almost everything with search but none of them helped except using the code that I provided directly in the template itself.
Edited based on comments below. You should be able to do this more simply by prefetching team members.
views.py
def tournament_page(request, slug):
page = 'tournament_page'
user = request.user
tournament = Tournament.objects.get(slug=slug)
all_players = Profile.objects.select_related('user')
side_tourneys_ongoing = Tournament.objects.filter(state='Ongoing')[:10]
side_tourneys_upcoming = Tournament.objects.filter(state='Upcoming')[:10]
side_tourneys_completed = Tournament.objects.filter(state='Completed')[:10]
teams = Team.objects.select_related('created_by').prefetch_related('members')
template.html
<div class="grid-x">
{% for team in teams %}
{% if team.game == tournament.game %}
<div class="wf-card event-team">
<div> {{team.title}} </div>
<div class="event-team-players">
{% for member in team.members.all %}
{{ member.username }}
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
</div>

How to pass a value from anchor tag to a function in views in Django

I have a model object movie and I want to pass movie.mid to addmovie function in views
views.py
def addMovie(request, mid):
uid = request.user.id
ob = MyMovies.objects(uid=uid, mid=mid, watched=True)
ob.save();
return redirect('/')
urls.py
path('addmovie/<int:mid>/', views.addMovie, name="addmovie"),
index.html
{% if movies %}
<section id="main">
<h2 class="latest-heading">Movies</h2>
<ul id="autoWidth2" class="cs-hidden">
{% for movie in movies %}
<li class="item-a">
<div class="latest-box">
<div class="latest-b-img">
<!-- <a href="{% url 'movieinfo' %}" title=""> -->
<img src={{ movie.cover }}>
<!-- </a> -->
</div>
<div class="latest-b-text">
<strong>{{movie.title}}</strong>
<p>{{movie.rdate}}</p>
</div>
{% if user.is_authenticated %}
<div>
Add to watched
</div>
<br>
{% endif %}
</div>
</li>
{% endfor %}
</ul>
</section>
{% endif %}
Even After passing the values correctly, the values in MyMovies are not updating. What am I doing wrong?
def addMovie(request, mid):
if request.method == "POST":
mid = request.POST['data'] # the problem is here, you are overriding mid default value
uid = request.user.id
try:
my_movie = MyMovies.objects.get(mid=mid)
my_movie.watched = True
except:
my_movie = MyMovies(uid=uid, mid=mid, watched=True)
my_movie.save()
return redirect('/')
you need to add movie.mid after url name, like Add to watched</div>
then, movie.mid will pass to url.py. And you need to add a parameter on url.py.
url.py
path('addmovie/<int:mid>/',views.addmovie)
then you need to pass to views.py
def addmovie(request,mid):

how to extract images for every single post in django

I have two different models. One is for posts and other one is for images.
what I want is to display all images for every single post. Here is the file for models:
class Cars_Posts(models.Model):
user = models.ForeignKey(MyUser, on_delete=models.CASCADE)
post_city = models.ForeignKey(City, on_delete=models.CASCADE)
post_title = models.CharField(max_length=256)
post_detail = models.TextField(max_length=65536)
price = models.PositiveIntegerField()
def __str__(self):
return "%s %s %s %s %s"(
self.user.id, self.post_city,
self.post_title, self.post_detail, self.price,)
class Images_Cars(models.Model):
post = models.ForeignKey(Cars_Posts, on_delete=models.CASCADE)
car_images = models.ImageField(upload_to='car_images', blank=True, null=True )
def __str__(self):
return "%s %s " % (self.post_id, self.car_images, )
Here is the view FUNCTION FOR SEARCH (QUERY DATA BASE):
def search(request):
template = 'path/to/template.html'
# get all cities in data base
all_p_cities = City.objects.all()
#get the exact city selected by user and passed through the variable h_qc
query_c = request.GET.get('h_qc')
# get posts under the selected city
result = Cars__Posts.objects.filter(Q(post_city__city_name__iexact=query_c)
# get posts IDs of the result object
p_id=[]
for item in result:
p_id+= [item.id]
# print(p_id)
#get all images under each single post
all_images=[]
for item in p_id:
images = Images_Cars.objects.filter(post_id = item)
all_images+=[images]
# print (p_id)
# print(result)
print(all_images)
context = {
'post_city' : query_c,
'result': result,
'all_images':all_images,
}
return render(request, template, context )
both files run with no error. However in the template I want to display all posts and all images for every single post. I need your help in here. I looped over results and could get all posts. But I got also all images for every single posts repeated in every loop. So , instead of getting only images related to the current post, I got all images for all posts in current post and all subsequent posts. Any help or suggestion will be appreciated. Also any suggestion for writing the code in view file with an efficient and sophisticated way is appreciated.
Here is portion of the HTML File:
{% csrf_token %}
{% for item in result %}
<li class="result-row">
<!-- image box -->
<span>
<a href="#" class="result-image-act" >
{% for image in all_images %}
<!-- if image list is empty display the default image -->
{% if not image %}
<img src="{% static 'path/to/default image' %}" class="active">
{% endif %}
<!-- I have class ="active" which is supposed to be class of first image -->
{% if image and image.0 %}
<img class="active" src="{{image.item.car_images.url}}" >
{% elif image and not image.0 %}
<img src="{{image.item.car_images.url}}" >
{% endif %}
{% endfor %}
</a>
<span class="embed-result-price">{{item.price}}</span>
<div class="swipe-wrap">
<div class="swipe-wrap-lef">
<span class="move" >
<div class="swipe-prev">
<p><</p>
</div>
</span>
</div>
<div class="swipe-wrap-rig">
<span class="move" >
<div class="swipe-next">
<p>></p>
</div>
</span>
</div>
</div>
</span>
<span class="result-price">{{result.price}}
</span>
<span class="result-price">{{result.title}}</span>
</li>
{% endfor %}
Note: inside the html javascript code that will take care of swipe images for every single post that is why I fetch for the first image for every single post to add class="active" to it
You can do it directly in templates with reverse related name:
add a property method in your ImageCars model to check whether files are actually exist
class Images_Cars(models.Model):
''' code '''
car_images = models.ImageField(upload_to='car_images', blank=True, null=True )
#property
def car_images_exists(self):
return self.car_images.storage.exists(self.car_images.name)
templates
{% for item in result %}
{% for image in item.images_cars_set.all %}
#<!-- The images_cars instance is here -->
{% if image.car_images_exists %} # see changes in models
{{image.car_images.url}}
{% endif %}
{% empty %}
#<!--Item has no image_cars instances here: item.images_cars_set.all -->
<h3>No Images</h3>
{% endfor %}
{% endfor %}
You don't really need to loop through the queryset in views and again in templates
result as template variable is enough to have everything in templates

How to display multiple images for django model

Here is my image model, that I tied to the model Product
class Image(models.Model):
name = models.CharField(blank=True,max_length=20)
product = models.ForeignKey(Product)
image = models.ImageField(blank=True,null=True)
def __str__(self):
return self.name
Here is the view that I am using to try and display the images
def category(request, category_id):
categories = Category.objects.all()
images = Image.objects.all()
products = Product.objects.all()
try:
category = Category.objects.get(id=category_id)
except Category.DoesNotExist:
category = None;
template = loader.get_template('index.html')
context = {
'category': category,
'categories': categories,
'images': images,
'products': products
}
return HttpResponse(template.render(context,request))
and here is the html
{% for image in images %}
<img src="{{ image.url }}">
{% endfor %}
I know this definitely wouldn't work,but atleast this code displays the page instead of an error so i have been using it, can anyone please point me in the right direction to dipslay each image associated with each product.
Thank you!
You can try this:
{% for product in products%}
<p> {{product.name}} </p>
{% for simage in product.image_set.all %}
{% if simage.image%}
<img src="{{ simage.image.url }}">
{% endif %}
{% endfor %}
{% endfor %}