Inserting multiple related model values in template with for loop - python

I am trying to post multiple values from different models in a for loop in a template. It is not doing what I am planning. I want to display a count of LeadActions that belong to Leads in a table. I did comment the part out that is not working as well. The table should display the list of Leads and the the count of how many overdue actions(LeadActions) there are for that specific lead.
My View
class LeadListView(LoginRequiredMixin, generic.ListView):
login_url = '/scrty/login/'
template_name = "nodiso/leadslist.html"
model = models.Leads
def get_context_data(self, **kwargs):
ctx = super(LeadListView, self).get_context_data(**kwargs)
ctx['actions']= models.LeadActions.objects.all()
return ctx
def get_queryset(self):
return models.Leads.objects.filter(company=self.request.session['compid'],archive=False)
My template
<table class="table">
<thead>
<th>Name</th>
<th>Overdue Tasks</th>
<th>Total Tasks</th>
</thead>
{% for lead in leads_list %}
{# {% for action in action_list %}#}
<tr>
<td>{{lead.name}}</td>
<td><span class="badge">{{ actions.name|length }}</span></td>
<td><span class="badge">42</span></td>
</tr>
{# {% endfor %}#}
{% endfor %}
</table>
The Models
class LeadActions(models.Model):
lead = models.ForeignKey(Leads)
name = models.CharField(max_length=265)
crdate = models.DateField(auto_now_add=True)
Duedate = models.DateField()
creator = models.CharField(max_length=265)
overdue = models.IntegerField(null=True,blank=True)
def __str__(self):
return self.name
class Leads(models.Model):
company = models.ManyToManyField(Company)
user = models.ManyToManyField(settings.AUTH_USER_MODEL)
name = models.CharField(max_length=265)
email = models.EmailField(max_length=265)
tel = models.IntegerField()
archive = models.BooleanField(default=False)
dateenq = models.DateField(auto_now_add=True,null=True)
def get_absolute_url(self):
return reverse('nodisoapp:leadlist')
def __str__(self):
return self.name

You shouldn't be sending the list of actions from the view. Instead, in the template, you can access {{ lead.leadactions_set.count }} to give the count of LeadActions related to each Lead in the loop.

Related

How to properly make a query in Django?

I've ran into a little problem. I want to construct a proper queryset to get values which represent the number of the expenses per category to display this like that.
This is what I got now:
class CategoryListView(ListView):
model = Category
paginate_by = 5
def get_context_data(self, *, category_object_list=None, **kwargs):
**categories = Category.objects.annotate(Count('expense'))
queryset = categories.values('expense__count')**
return super().get_context_data(
category_object_list=queryset,
**kwargs)
Of course it doesnt work and I have terrible table like this. I suppose the problem isn't in HTML but in my absolutely wrong query... What should I do?
This is my HTML in case it would be needed:
{% for category in object_list %}
<tr>
<td>
{{ category.name|default:"-" }}
</td>
<td>
{% for number in category_object_list %}
{{ number.expense__count }}
{% endfor %}
</td>
<td>
edit
delete
</td>
{% endfor %}
</tr>
Also my models.py:
class Category(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return f'{self.name}'
class Expense(models.Model):
class Meta:
ordering = ('-date', '-pk')
category = models.ForeignKey(Category, null=True, blank=True,
on_delete=models.CASCADE)
name = models.CharField(max_length=50)
amount = models.DecimalField(max_digits=8, decimal_places=2)
date = models.DateField(default=datetime.date.today, db_index=True)
def __str__(self):
return f'{self.date} {self.name} {self.amount}'
You can try like this within your template with the reverse look up of
Foregin Keys. See the docs for more detail.
{% for category in object_list %}
<tr>
<td>
{{ category.name|default:"-" }}
</td>
<td>
{{category.expense_set.all.count}}
</td>
<td>
edit
delete
</td>
{% endfor %}
</tr>
Now in the view you can just pass all the categories with the ListView
class CategoryListView(ListView):
model = Category
paginate_by = 5

How to fetch data from different tables in Django?

I am new to Django and Python,
I have a table for clients, and one for trips. I can display the clients on the clients page, and the same for the trips.
But on the clients page, I want to show all the trips that are linked to each client. And this is where I hit a wall.
This is my models.py
from django.db import models
from django.core.validators import RegexValidator
# Create your models here.
class Clientes(models.Model):
nome = models.CharField(max_length=30)
apelido = models.CharField(max_length=30)
morada = models.CharField(max_length=200)
tel = models.CharField(max_length=9, validators=[RegexValidator(r'^\d{1,10}$')])
nif = models.CharField(max_length=9, validators=[RegexValidator(r'^\d{1,10}$')])
def __str__(self):
return "%s %s" % (self.nome, self.apelido)
class Meta:
verbose_name_plural = "Clientes"
class Viagem(models.Model):
trip_id = models.CharField(max_length=30)
cliente = models.ForeignKey(Clientes, on_delete=models.CASCADE)
comp = models.CharField(max_length=30)
data = models.DateField()
destino = models.CharField(max_length=30)
def __str__(self):
return self.trip_id
class Meta:
verbose_name_plural = "Viagens"
This is my views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Clientes, Viagem
# Create your views here.
def index(request):
ls= Clientes.objects.all()
context = {'ls': ls}
return render(request, "booking/home.html", context)
def cliente(request, id):
ls= Clientes.objects.filter(id=id)
context = {'ls': ls}
return render(request, "booking/cliente.html", context)
def trip(request):
ls= Viagem.objects.all()
context = {'ls': ls}
return render(request, "booking/trip.html", context)
and this is the table on the home.html
<table id="selector" class="table is-fullwidth is-hoverable">
<thead>
<tr>
<th>Nome</th>
<th>Apelido</th>
<th>Morada</th>
<th>Telemóvel</th>
<th>NIF</th>
<th>Viagens</th>
</tr>
</thead>
<tbody>
{% for ls in ls %}
<tr>
<td>{{ls.nome}}</td>
<td>{{ls.apelido}}</td>
<td>{{ls.morada}}</td>
<td>{{ls.tel}}</td>
<td>{{ls.nif}}</td>
<td>{{ls.trip_id}}</td>
</tr>
{% endfor %}
</tbody>
</table>
I assume it has something to do with ForeignKey, but a ForeignKey on the first class won't work.
I thought about creating a new def on the views.py using the Viagem table and a diferent context, but that also doesn't seem to be the solution.
So, anyone can point me in the right direction?
In your views.py, specifically the cliente function, you want to add the following line:
viagems=Viabem.objects.filter(cliente=ls)
modify the following line:
ls= Clientes.objects.filter(id=id)
so that it now shows:
ls=Clientes.objects.get(id=id)
and then change your context to equal:
context = {'ls': ls, 'viagems': viagems}
then you will be able to iterate over the different viagems in your html template file with the following kind of structure:
{% for viagem in viagems %}
{{ viagem.whatever_field }}
{% endfor %}
and that should be it, I believe...
Since you are filtering by ID (fetching single object), this is one of the options to go:
views.py
from django.shortcuts import get_object_or_404
def cliente(request, id):
ls = get_object_or_404(Clientes, id=id)
trips = obj.viagem_set.all()
context = {'ls': ls, 'trips': trips}
return render(request, "booking/cliente.html", context)
template.html
<table id="selector" class="table is-fullwidth is-hoverable">
<thead>
<tr>
<th>Nome</th>
<th>Apelido</th>
<th>Morada</th>
<th>Telemóvel</th>
<th>NIF</th>
<th>Viagens</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ls.nome}}</td>
<td>{{ls.apelido}}</td>
<td>{{ls.morada}}</td>
<td>{{ls.tel}}</td>
<td>{{ls.nif}}</td>
<td>{% for trip in trips %}{{ trip.id }}{% endfor %}</td>
</tr>
{% endfor %}
</tbody>
While I'm not sure why you need to show record ID's in the table.
#João de Sousa, I found you want to show all trips that are associated with each client.
First of all you have to get a single client by his id obj = clients.objects.get(id = id) then this id pass to referred model like this obj1 = Viagem.objects.filter( id = obj.id)
According to my understanding from your above posted question is that you want to get help about how you get data from reference model/table. Django provides very easy and flexible way to get data from tables.
Feel free to ask any question if you need more clarification.

How to get list of all objects of logged in user's here in django?

I tried getting the list of objects from the current logged users. There something missing in the codes.
I wrote a class-based view as well as function-based views.
Class-based views give an error like 1 positional argument but two were given.
And in function-based view it giving only first item instead looping through it.
I want to show the pass investments inventory record of each investor.
Thank you!
views.py (Function-Based Views)
def InvestmentListView(request):
investors = Investment.objects.all(id=request.user.id)
args = {'investors':investors}
return render(request, 'investors/myinvest.html', args)
This only retrieving an only first item.
views.py (class-Based viewa)
class InvestmentListView(ListView):
model = Investment
template_name = 'investors/myinvest.html'
context_object_name = 'total_invested_by_user'
def get_queryset(self):
return Investment.objects.filter(investor=self.request.user.id)
This CBV gives an error like 1 positional argument, but 2 were given.
myinvest.html
<div class="container">
{% if user.is_authenticated %}
<h2>Investor Name: {{ request.user }}</h2>
<table>
<tr>
<th>Amount Invested</th>
<th>Date</th>
<th>Rate Of Interest</th>
<th>Return</th>
<th>Profit</th>
</tr>
<tr>
{% for invest in investors %}
<th>{{ invest.amount }}</th>
<th>{{ invest.timestamp }}</th>
<th>{{ invest.rate }}</th>
<th>None</th>
<th>None</th>
{% endfor %}
</tr>
</table>
{% endif %}
Here, models.py
class Investor(models.Model):
name = models.CharField(max_length=99)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Investment(models.Model):
amount = models.FloatField(blank=False)
rate = models.FloatField(blank=False)
timestamp = models.DateField(default=datetime.now)
investor = models.ForeignKey(Investor, on_delete=models.CASCADE)
def __str__(self):
return str(self.investor)
You are filtering the Investment id with your user id which is not correct. This should work:
investors = Investment.objects.filter(investor__user=request.user)

Saving Django form data to a User

I'm creating a website for general education uses and one of the features is a calendar section where I would like the user to be able to store their events but then when they login they can view the events they created. This is for an academic assignment.
I can't seem to get this calendar to link to a user field. I would like each record in the calendar table to have a user_id which will be the same as the current_user. I understand that you can user the django default user auth but i have not done that due to not knowing about it and by the time I realized it was too late.
So all I really need to do is when the form is valid, I need to assign the value of the current_user id as the value for student in the calendar table. But for some reason I keep getting problems and the form isn't detected as being valid or the program just doesn't assign the value.
My main objective is to have each user view their own calendar. I don't mind changing the current student field to a foreign key field
Student.Views
def calendar(request):
student_obj = Student.objects.get(student_name=current_user)
print(student_obj)
if request.method == 'POST':
form = EventsForm(initial={'student': '3'} or request.POST)
print(form.errors)
if form.is_valid():
form.save()
all_events = Events.objects.filter(student=student_obj.id)
messages.success(request, 'Event Has Been Added')
return render(request, 'Student/calendar.html', {'all_events': all_events})
else:
messages.success(request, 'Event Has NOT Been Added')
all_events = Events.objects.filter(student=student_obj.id)
return render(request, 'Student/calendar.html', {'all_events': all_events})
Student.Models
class Student(models.Model):
student_name = models.CharField(max_length=59, default=None)
username = models.CharField(max_length=59)
password = models.CharField(max_length=59)
age = models.PositiveIntegerField()
date_of_birth = models.DateField(max_length=10)
form = models.CharField(max_length=3)
email = models.EmailField(max_length=59)
present = models.PositiveIntegerField(default=0)
late = models.PositiveIntegerField(default=0)
absent = models.PositiveIntegerField(default=0)
maths_grade = models.PositiveIntegerField(default=0)
english_grade = models.PositiveIntegerField(default=0)
science_grade = models.PositiveIntegerField(default=0)
behaviour_level = models.PositiveIntegerField(default=0)
def __str__(self):
return self.student_name
class Events(models.Model):
student = models.CharField(max_length=200)
date = models.DateField(max_length=10, default=None)
event = models.CharField(max_length=200)
completed = models.BooleanField(default=False)
Student.forms
class EventsForm(forms.ModelForm):
class Meta:
model = Events
fields = ["event", "completed", "date", "student"]
Calendar Template
<div class="container" style="color: #fff">
<br/>
{% if messages %}
{% for message in messages %}
<div class="alert alert-warning alert-dismissible" roles="alert">
<button class="close" data-dismiss="alert">
<small>x</small>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% if all_events %}
<div>
<table class="table table-dark table-bordered">
{% for things in all_events %}
{% if things.completed %}
<style>
.striker {
text-decoration: line-through;
text-color: black;
}
</style>
<tr class="table-danger striker">
<td style="color: black">{{ things.date }}</td>
<td>{{ things.event }}</td>
<td><center>Delete</center></td>
</tr>
{% else %}
<tr>
<td>{{ things.date }}</td>
<td >{{ things.event }}</td>
<td><center>Delete</center></td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
{% endif %}
Change form.save() to
event = form.save(commit=False)
event.student = request.user
event.save()
That'll do it.
Don't make it complicated, this have to be easier. If I understood what are you trying to do I would create my models as following:
#model.py
from django.db.models.signals import post_save
from django.dispatch import receiver
class Student(models.Model):
user= models.OneToOneField(User, null=True) #student is user
#Define student fields...
class Calendar(models.Model):
#Defile calender fields here along with its default values ...
user = models.OneToOneField(Student)
'''
this signal populate calender table with user_id along with its
calender fields
'''
#receiver(post_save, sender=Student)
def create_student_calender(sender, instance, created, **kwargs):
if created and not kwargs.get('raw', False):
calendar = Calender(user=instance)
calendar.save()
class Event(models.Model):
calender = models.ForeignKey(Callender, null=True)
# Define event fields here ...
With models structure like this, whenever student create account Calendar model will be populated saved with calendar fields and student's id field.
So how do student create their events? Simply create an a inlineformset_factory form to create events on each student's calendar like this:
#form.py
from django.forms import inlineformset_factory
from django import forms
class EventForm(forms.ModelForm):
#Events form fields here...
class Meta:
model = Event
fields = ["Event's field"]
EventFormSet = inlineformset_factory(Calender, Event, form=EventForm,
max_num=1, can_delete=False)
Render this formset with a view for student to create their events,the formset automatically associate student's event to calendar.
So you can add your logic to do more.

Django duplicate database lookups with inlineformset

I need help with solving an issue regarding duplicate database query's for each form in an inlineformset. I have a page where users can add and edit books belonging to an author.
models.py
from django.db import models
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
class Book(models.Model):
id = models.AutoField(primary_key=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
category_idcategory = models.ForeignKey(Category, models.DO_NOTHING)
class Category(models.Model):
name = models.CharField(max_length=100)
forms.py
from django import forms
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
views.py
instance = get_object_or_404(Author, id=id)
form = inlineformset_factory(Author, Book, form=BookForm, can_delete=True, extra=5)
formset = form(request.POST or None, instance=instance)
if request.method == "POST":
if formset.is_valid():
instanceForm = formset.save(commit=False)
for obj in instanceForm:
obj.save()
for obj in formset.deleted_objects:
obj.delete()
return HttpResponseRedirect(URL)
When I run the template, it performs a database query to the Category model for each form in formset. How do I prevent those duplicates? I dont know where to put select_related or prefetch_related. If instances of Book model grows to a large number, the page load times are getting very slow.
template.html
<table class="table table-sm">
{{ formset.management_form }}
<thead>
<td>Title</td>
<td>Category</td>
<td>delete</td>
</thead>
<tbody>
{% for obj in formset %}
{{ obj.id }}
<tr>
<td>{{ obj.title }}</td>
<td>{{ obj.category_idcategory }}</td>
<td>{{ obj.DELETE }}</td>
</tr>
{% endfor %}
</tbody>
</table>
You can change the queryset of a formset like this:
class InlineBookFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Here is where to put the select_related.
self.queryset = Book.objects.select_related('category_idcategory').all()
then in your factory method call:
# Use your custom InlineBookFormSet
form = inlineformset_factory(Author, Book, form=BookForm, can_delete=True, extra=5, formset=InlineBookFormSet)

Categories