Django show image list in table from ManyToMany field - django

I have created a model to have details of job vacancy. The job model has the following fields:
class Job(models.Model):
job_position = models.ForeignKey(Position, on_delete=models.PROTECT, related_name='job_position')
applicants_to_hire = models.IntegerField(null=True, blank=True,
validators=[MinValueValidator(1), MaxValueValidator(15)], default=1)
hiring_team = models.ManyToManyField(Employee, related_name='hiring_team')
class JobListView(LoginRequiredMixin, ListView):
model = Job
template_name = 'recruitment/job_list.html'
context_object_name = 'job_list'
I want to use the hiring_team in a template to show image of each employee (circle avatar), and those images come from the employee model:
class Employee(models.Model):
image = models.ImageField(blank=True, default='blank_profile_picture.jpg')
I've managed to display all images, but they are not in the same table cell, and they add additional table columns:
<tbody>
{% for job in job_list %}
<tr>
<td><span class="employee-table-name">{{ job.job_position }}</span></td>
<td>{{ job.applicants_to_hire }}</td>
{% for team in job.hiring_team.all %}
{% if team.image %}
<td><img src="{{ team.image.url }}" class="rounded-circle img-fluid-80" alt="{{ team }}"></td>
{% endif %}
{% endfor %}
<td>{{ job.job_priority }}</td>
<td>{{ job.job_status }}</td>
<td>{{ job.created|date:"M d, Y" }}</td>
</tr>
{% endfor %}
</tbody>
How can I "concatenate" them to display something like the screenshot below:

This should mean the images should all be under one td block, so just put the td outside of the loop:
<td>
{% for team in job.hiring_team.all %}
{% if team.image %}
<img src="{{ team.image.url }}" class="rounded-circle img-fluid-80" alt="{{ team }}">
{% endif %}
{% endfor %}
<td>

Related

don't show images from ImageField in django template

Django doesn't show images from ImageField in a template.
models.py
class Employee(models.Model):
emp_name = models.CharField(max_length=200)
emp_email = models.EmailField()
emp_contact = models.CharField(max_length=20)
emp_role = models.CharField(max_length=200)
emp_salary = models.IntegerField()
venue_image = models.ImageField(null=True, blank=True, upload_to="images/")
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
def __str__(self):
return self.emp_name
template:
<tbody>
{% for emp in employees %}
<tr>
<th scope="row">{{ emp.emp_name }}</th>
<td>{{ emp.emp_email }}</td>
<td>{{ emp.emp_contact }}</td>
<td>{{ emp.emp_role }}</td>
<td>{{ emp.emp_salary}}</td>
<td>
<a style="margin-right: 30px;" href="{% url 'edit-employee' emp.id %}">EDITAR</a>
ELIMINAR
</td>
<td>
{%if venue.venue_image%}
{{venue.venue_image.url}}
{%endif%}
</td>
</tr>
{% endfor %}
</tbody>
views.py
I'm expecting the image here:
The issue is with your if condition in your template. You are getting your employees data with for loop and using variable emp not venue. Use this if condition and your image url will be displayed
{% if emp.venue_image %}
{{emp.venue_image.url}}
{% endif %}
If you want to display the image you need to use image tag like this
{% if emp.venue_image %}
<img src="{{emp.venue_image.url}}">
{% endif %}

How do I bring through my data in Django Template view?

I'm trying to display my data from my HealthStats model to my template, however I can only pull through the user field. I've added the other fields to my template, but they're not showing. I would also like to be able to filter the output to only show records of the logged in user.
Models.py
class HealthStats(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateField(auto_now=True)
weight = models.DecimalField(max_digits=5, decimal_places=2)
run_distance = models.IntegerField(default=5)
run_time = models.TimeField()
class Meta:
db_table = 'health_stats'
ordering = ['-date']
def __str__(self):
return f"{self.user} | {self.date}"
Views.py:
class HealthHistory(generic.TemplateView):
model = HealthStats
template_name = 'health_hub_history.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['stats'] = HealthStats.objects.all()
return context
health_hub_history.html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 text-center">
<h1>My Health History</h1>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<table class="table table-striped table-hover table-bordered">
<tr>
<td>User:</td>
<td>Weight (lbs):</td>
<td>Date:</td>
<td>Run Distance (km):</td>
<td>Run Time (HH:MM:SS):</td>
</tr>
{% for stat in stats %}
<tr>
<td>{{ user }}</td>
<td>{{ weight }} </td>
<td>{{ date }}</td>
<td>{{ run_distance }}</td>
<td>{{ run_time }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endblock content %}
Any help would be appreciated!
In your template do this:
{% for stat in stats %}
<tr>
<td>{{stat.user}}</td>
<td>{{stat.weight}} </td>
<td>{{stat.date}}</td>
<td>{{stat.run_distance}}</td>
<td>{{stat.run_time}}</td>
</tr>
{% endfor %}
hope it will work

Displaying data from intermediate table in a many-to-many relation

I have 3 models that follow the principle described in Django documentation (https://docs.djangoproject.com/en/2.2/topics/db/models/#extra-fields-on-many-to-many-relationships):
class Topic(models.Model):
key = models.CharField(max_length=255, primary_key=True)
persons = models.ManyToManyField('Person', through='Interest')
class Person(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
interests = models.ManyToManyField('Topic', through='Interest')
class Interest(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
source = models.ForeignKey(TopicSource, on_delete=models.CASCADE)
The views.pyis really simple:
class TopicsView(generic.ListView):
template_name = 'app/topics.html'
context_object_name = 'topics_list'
def get_queryset(self):
return Topic.objects.all()
The template is actually giving me headaches:
<table>
<tbody class="list">
{% for item in topics_list %}
<tr>
<td>{{ item.key }}</td>
<td>{{ item.person_set.all.count }}</td>
<td>
<ul>
{% for person in item.person_set.all %}
<li>{{ person.last_name }}, {{ person.first_name }} [{% person.interests_set.get(cluster=item) %}]</li>{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
With {% person.interests_set.get(topic=item) %}, I'm trying to access data from the intermediate table.
How can I display the source of the interest next to the name of the person?
This solution is giving hint on how to do this from the shell but I cannot figure out how to achieve that in the template.
Django templates don't support what you're trying to do out of the box. You would have to create a custom tag to implement what you're trying.
However you could do:
class TopicsView(generic.ListView):
template_name = 'app/topics.html'
context_object_name = 'topics_list'
queryset = Topic.objects.prefetch_related(
Prefetch(
'interest_set',
Interest.objects.select_related('person')
)
Then adjust your template to iterate over the interests.
<table>
<tbody class="list">
{% for item in topics_list %}
<tr>
<td>{{ item.key }}</td>
<td>{{ item.interest_set.all.count }}</td>
<td>
<ul>
{% for interest in item.interest_set.all %}
<li>{{ interest.person.last_name }}, {{ interest.person.first_name }} [ {{ interest.source }} ]</li>{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
As an alternative to the solution proposed by #schillingt (the accepted solution), I came up with the below solution:
views.py:
class InterestsView(generic.ListView):
template_name = 'app/interests.html'
context_object_name = 'interests_list'
def get_queryset(self):
return Interest.objects.order_by('topic', 'person').all()
template:
{% regroup interests_list by topic as l1%}
<table>
<tbody>
{% for topic in l1 %}
<tr>
<td>{{ topic.grouper }}</td>
<td>{{ topic.list|length }}</td>
<td>
<ul>
{% for item in topic.list%}
<li>{{ item.person.last_name }}, {{ item.person.first_name }} [{{ item.source }}]</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
However, the solution from #schillingt is better since it's performance are a lot better (by a factor 2),

Django dynamically filter list in template

I have a page which lists all of the athletes that a certain coach has. Coaches, however, can have multiple teams and I am trying to allow them to select a team from a dropdown at the top of the page and dynamically filter the list of athletes to only show those on the selected team.
My template:
<table class='table'>
<tr>
<td><h3>Team</h3></td>
<td><h3>First Name</h3></td>
<td><h3>Last Name</h3></td>
<td><h3>Email</h3></td>
</tr>
{% for athlete in athletes %}
{% if not athlete.coach_ind %}
<tr><td>
{% for team in athlete.team.all %}
{{ team.school }} {{ team.mascot }} {{ team.sport }}
{% endfor %}
</td>
<td>{{ athlete.user.first_name }}</td>
<td>{{ athlete.user.last_name }}</td>
<td>{{ athlete.user.email }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
My view:
teams_list = request.user.profile.team.all()
athletes = UserProfile.objects.filter(team__in=teams_list).order_by('team','user__last_name')
I am able to successfully get the correct list of all athletes and their information, I'm just not sure how to create a dynamic filter to show only by team.
You can use django-filter for it https://github.com/alex/django-filter.
Example from documentation:
Model
class Product(models.Model):
name = models.CharField(max_length=255)
manufacturer = models.ForeignKey(Manufacturer)
Filter
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['manufacturer']
View
def product_list(request):
f = ProductFilter(request.GET, queryset=Product.objects.all())
return render_to_response('my_app/template.html', {'filter': f})
Template
{% block content %}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit" />
</form>
{% for obj in filter %}
{{ obj.name }}<br />
{% endfor %}
{% endblock %}
Another app to those for this type of "chained" selection is selectable (http://django-selectable.readthedocs.io/en/latest/advanced.html#chained-selection). You have to put some additional javascript to the template, though.

How to get the fields from object_list in django template

I am using this as Generci view
book_info = {
"queryset" : Book.objects.all(),
"template_name" : "book/book_lists.html",
}
Now in my template book_lists i have
{% for book in object_list %}
<tr>
<td>{{ book.name }}</td>
Is there any way i can loop through all like we have in form
{% for field in form %}
forn.label_tag and field
so that i can use it for all Models
so basically i want something like
{% for obj in object_list %}
<tr>
{% for fields in obj %}
<td> {{field.name}}:{{field}} </td>
You need to create a get_fields function in your model(s) which you can then use in the templates to access the fields and values generically. Here is a complete example.
books/models.py:
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=30)
author = models.CharField(max_length=30)
isbn = models.IntegerField(max_length=20)
published = models.BooleanField()
def get_fields_and_values(self):
return [(field, field.value_to_string(self)) for field in Book._meta.fields]
templates/books/book_list.html:
<table>
{% for obj in object_list %}
<tr>
{% for fld, val in obj.get_fields_and_values %}
<td>{{ fld.name }} : {{ val }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>