Django template rendering relational modelobject names without duplicates - django

So I have been trying to figure out how to render related objects in a template. I have been trying to do it with the query-set in the template, but i might be totally wrong and I need to do something with the context instead. Either way I have no idea what I'm supposed to do.
What i want to do:
Get a query-set with the tips that are going to be published.
With the help of the query-set render a list of tips for the city. The list itself is the station and the number of tips for said station and the total number of tips for the specific region.
What i want to render in my template
Uptown (3)
K-Jah (2)
Chatterbox FM (1)
Staunton Island (1)
Lips 106 (1)
What i have been trying with:
<table>
{% for object in object_list %}
<tr>
<th>Region</th>
</tr>
<tr>
<td>{{ object.station.region }} </td>
<tr>
<th>Station</th>
<td>{{ object.station.name }}</td>
{% endfor %}
</table>
Now this is clearly wrong and I know it. It loops over and renders the same region and station name several times and I don't render the number of times a region or station appears in the loop.
I have my models setup like below:
models.py
class Tip(models.Model):
name = models.TextField(verbose_name=_('name'), blank=True, null=True)
email = models.EmailField(verbose_name=_('email'), max_length=50, blank=True, null=True)
description = models.TextField(verbose_name=_('description'), blank=True, null=True)
comment = models.TextField(max_length=255, blank=True, null=True)
published = models.BooleanField(default=False, verbose_name=_('published'))
class NamedModel(models.Model):
name = models.CharField(verbose_name=_('name'), max_length=255)
def __unicode__(self):
return u'%s' % self.name
class Region(NamedModel):
def __unicode__(self):
return u'%s' % self.name
class Station(models.Model):
name = models.CharField(verbose_name=_('name'), max_length=255)
phone = models.CharField(verbose_name=_('phone'), max_length=255, blank=True)
region = models.ForeignKey(Region, verbose_name=_('region'))
def __unicode__(self):
return u'%s' % self.name
class StationTip(Tip):
station = models.ForeignKey(Station, verbose_name=_('station'))
def __unicode__(self):
return u'%s' % self.school
The query-set:
K-Jah region = Uptown
Chatterbox region = Uptown
Lips 106 region = Staunton Island
StationTip.objects.all().filter(published=True)
What the query-set returns:
[<StationTip: K-Jah>, <StationTip: K-Jah>, <StationTip: Lips 106>, <StationTip: Chatterbox FM>]

What you want to use is the annotate function in combination with the values function:
from django.db.models import Count
tips = StationTip.objects.filter(published=True).values('station__name', 'station__region').annotate(count=Count('id'))
This will create a list with a dictionary for each unique combination of station.name and station.region, with an extra key count and the number of occurrences.
And in your template (if you pass tips as object_list):
<table>
{% for object in object_list %}
<tr>
<th>Region</th>
<th>Station</th>
<th>Count</th>
</tr>
<tr>
<td>{{ object.station__region}} </td>
<td>{{ object.station__name }}</td>
<td>{{ object.count }}</td>
</tr>
{% endfor %}
</table>

Related

Django, Unable to view certain database information

I've been working on a project and I've been stuck for over a week and haven't been able to find the solution to this problem.
I'm creating a school management app. I've successfully allowed the teachers to create a schedule, allowed the students to view it and select it as part of their class. The problem I'm running into is that the teacher is not able to see the students information after they've chosen a class.
For models I have:
class Student(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
englishName = models.CharField(max_length=200)
studentName = models.CharField(max_length=200)
studentId = models.CharField(max_length=200)
birthday = models.DateField()
gender = models.CharField(max_length=6)
gradeLevel = models.CharField(max_length=8)
since = models.DateField()
duration = models.CharField(max_length=3)
contactNumber = models.CharField(max_length=13, default=00000000)
email = models.EmailField(max_length=200, default='address#email.com')
def __str__(self):
return self.studentName
def index(request):
data=Student
context = {'form': data}
return render(request, 'student-information.html', context)
class Schedule(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date = models.DateField(null = True, blank = True)
time = models.TimeField(null = True, blank = True)
duration = models.TextField(null = True, blank = True)
capacity = models.PositiveSmallIntegerField(default=1)
student = models.ForeignKey(Student, null = True, on_delete=models.CASCADE)
def __datetime__(self):
return self.date + '' + self.student
def index(request):
data = Schedule
context = {'form': data}
return render(request, 'set-schedule.html', context)
For my views file I have:
#login_required
#allowed_users(allowed_roles=['teacher'])
def dailySchedule(request):
today = datetime.now().date()
schedules = Schedule.objects.filter(date=today)
students = []
for schedule in schedules:
students.append(schedule.student)
context = {'today': datetime.now().date(), 'schedules': schedules, 'students': students}
return render(request, 'eslbeeph/daily-schedule.html', context)
and for the html file I have:
{% extends 'main.html' %}
{% block content %}
<div class="container-fluid">
<div class="daily-schedule-title">
<h3 class="daily-schedule-header">Schedule</h3>
</div>
<!--Information to be obtained by from the database.-->
<div class="daily-schedule-table">
<table class="daily-schedule">
<tr>
<th>Date</th>
<th colspan="6">{{ today|date:"F d, Y" }}</th>
</tr>
<tr>
<th>Start Time</th>
<th>Account</th>
<th>Duration</th>
<th>Student ID</th>
<th>Student Name</th>
<th>Class Status</th>
<th>Student Profile</th>
</tr>
{% for schedule in schedules %}
<tr>
<td>{{ schedule.time|date:"H:i" }}</td>
{% for student in students %}
<td>{{ schedule.student.user.username }}</td>
<td>{{ schedule.duration }}</td>
<td>{{ schedule.student.studentId }}</td>
<td>{{ schedule.student.englishName }}</td>
{% endfor %}
<td>{ status }</td>
<td></td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock content %}
Now, There's a lot more code to the project but these are the areas I think are causing the problem. I've tried a number of different things to get this to work, but nothing's worked.
If anyone can see where I'm going wrong or what I need to do let me know. I appreciate any help anyone can give me.
What I've been trying to do is get the a table to show up with the schedule time, the user name of the student who selected the schedule, the number of minutes the teacher stated the class would be, the students id number, and the students english name. The class status and the button for the students profile I plan to handle later.
Right now the time and the class length show up fine. But no matter what I do I cannot get the students user name, english name, and ID to populate at all.
Any tips, examples, or guesses as to why this is happening would be appreciated.
EDIT
After doing a bit more work I found that the Student model is not connecting to the Schedule model. So, the problem is different from what I originally suspected. It's not that the student information isn't being shown. It's that the schedule a student selects isn't recognizing the student has selected it.

How to count model ForeingKeys instances per row in a template table?

I want to count how many "plans" does a "client" have per table row in my template, there's a bit of the code
urls.py>>> urlpatterns = [ path('clients/', views.indexClient, name='clients'),]
models.py
class Plan (models.Model):
name = models.CharField(max_length=100, unique=True)
client = models.ForeignKey('Client', on_delete=models.RESTRICT)
gp_code = models.CharField(max_length=13, primary_key=True)
dispatch_conditions = models.TextField()
elaboration = models.CharField(max_length=100)
reviewer = models.CharField(max_length=100)
def __str__(self):
return self.product
------------------------------------------------------------------------------------
class Client (models.Model):
name = models.CharField(max_length=100, unique=True)
rif_num = models.CharField(max_length=10, primary_key=True)
def __str__(self):
return self.name
views.py
from django.db.models import Count
from .models import *
def indexClient(request):
client_list = Client.objects.all()
plans = Client.objects.annotate(num_plan = Count('plan'))
template = loader.get_template('app/clients.html')
context={'client_list':client_list, 'plans':plans}
return HttpResponse(template.render(context, request))
template clients.html
<table>
<thead>
<tr>
<th>Client</th>
<th >Plans</th>
</tr>
</thead>
<tbody>
{% for client in client_list %}
<tr>
<td>{{ client.name }}</td>
<td>{{ plans.num_plan }}</td>
</tr>
{% endfor %}
</tbody>
</table>
i tried to apply the methods said in this, this and this question but it didn't work for me or i'm applying the Count() incorrectly
want the table to display just like...
Client
Plans
Jhon
2
Mark
4
Louis
0
Vic
1
but currently the 'Plans' displays blank like this...
Client
Plans
Jhon
Mark
Louis
Vic

How to get two models data in for loop with filter: Django

I do have two model as below, like patient details model and patient visit model. I want to list the visits of all patients (if exist). in views.py I am passing both models data by get all. how to filter and show it in the template by using for loop. I am using two for loop it shows total number of patient multiply total number of visit which is wrong..
class patientprofile(models.Model):
pat_Fname = models.CharField(max_length=100)
pat_Lname = models.CharField(max_length=100, blank=True)
def IntegerField(self):
return self.id
class visits(models.Model):
pat_ID = models.ForeignKey(patientprofile, on_delete=models.CASCADE)
visit_date = models.DateField(blank=False, null=False)
visit_time = models.TimeField(blank=False, null=False)
views.py
#login_requireddef visitslist(request):
patpro=patientprofile.objects.all()
vis=visits.objects.all()
return render(request, 'pmp/visitslist.html', {'vis':vis, 'patpro':patpro})
Template as below
{% for a in vis %}
<tr>
<td>
{{ a.visit_time }}
</td>
<td>{{ a.visit_date }}</td>
<td>{{ patpro.id }}</td>
<td>{{ patpro.pat_Fname }}</td>
</td>
</tr>
{% endfor %}
You can easily transform it into a dict object using values() function in queryset object.
for example:
merged_tables_dict = visits.objects.values('visit_date', 'visit_time', 'pat_ID__pat_Fname', 'pat_ID__pat_Lname')
That will return a list of objects with all data in values params
You can read more about it Django Docs values

Django template display different models fields

I'm trying to list fields from few models in a table in template. The models are joined by different fields as in below snippet:
models.py:
class Client(models.Model):
clientID = models.IntegerField(primary_key=True)
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=50)
pesel = models.CharField(max_length=11)
#property
def loan(self):
return self.loan_set.all().first()
class Loan(models.Model):
clientID = models.ForeignKey(Client, on_delete=models.CASCADE)
loanNo = models.CharField(max_length=10)
class Case(models.Model):
loanID = models.ForeignKey(Loan, on_delete=models.CASCADE)
caseID = models.CharField(max_length=30, primary_key=True)
callForPaymentDate = models.DateField(default=None)
class Phase(models.Model):
caseID = models.ForeignKey(Case, on_delete=models.CASCADE)
phaseTypeID = models.ForeignKey(PhaseType, on_delete=models.CASCADE)
courtID = models.TextField(max_length=200)
class PhaseDetail(models.Model):
caseID = models.ForeignKey(Case, on_delete=models.CASCADE)
phaseTypeID = models.ForeignKey(PhaseType, on_delete=models.CASCADE)
dismissalDate = models.DateField(default=None, blank=True, null=True)
As you see above models are connected by ForeignKey. How do I pass those models in a view (views.py below):
def index(request):
clients = Client.objects.all()
cases = Case.objects.all()
phasedetails = PhaseDetail.objects.all()
phases = Phase.objects.all()
loans = Loan.objects.all()
return render(request, 'erepertorium/index.html',
{'clients': clients, 'cases': cases, 'phasedetails': phasedetails,
'phases': phases, 'loans': loans})
So that I can display different models fields but matched by this ForeignKey?
See below html template:
<table id="case_list" class="display">
<thead>
<tr>
<td>Sygnatura wg Powoda</td>
<td>Sygnatura EPU</td>
<td>PESEL</td>
<td>Numer pożyczki</td>
<td>Imię i nazwisko</td>
</tr>
</thead>
<tbody>
<tr></tr>
{% for c in clients %}
<tr>
<td>{{ c.case.caseID }}</td>
<td>2</td>
<td>{{ c.pesel }}</td>
<td>{{ c.loan.loanNo }}</td>
<td>{{ c.firstName }} {{ c.lastName }}</td>
</tr>
{% endfor %}
</tbody>
</table>
I've read some solutions about class based views etc. but some of the solution would require rebuilding whole models thing (over 200 lines of code). So before I do that I'd like to ask Community for help.
I know two ways that you can achieve it.
First off with a #property:
class Client(models.Model):
clientID = models.IntegerField(primary_key=True)
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=50)
#property
def loan(self):
return self.loan_set.all().first()
the template would be:
<td>{{ c.loan.loanNo }}</td>
Or
in template, you access it via the reverse relation
<td>{{ c.loan_set.all.0.loanNo }}</td>
Make sure that before the reverse relation the instance owns the relation. with if self.loan_set.all()(Model) | {% if c.loan_set.all %} (Template)

How to get a value from related object in a django template

I'm quite new with python and django and I apologize if the topic was already covered, but I coudln't find an answer to my question.
I have theese classes in my models.py
class Category(models.Model):
category_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.category_type
class Area(models.Model):
area_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.area_type
class Topic(models.Model):
topic_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.topic_type
class Tag(models.Model):
tag_type = models.CharField(max_length=50)
description = models.TextField()
def __unicode__(self):
return self.tag_type
class GenericRecord(models.Model):
document_title = models.CharField(max_length=500)
category = models.ForeignKey("Category")
area = models.ForeignKey("Area")
topic = models.ForeignKey("Topic")
tag = models.ForeignKey("Tag")
note = models.TextField(null=True, blank=True)
link = models.TextField(null=True, blank=True)
file_upload = models.FileField(upload_to='GenericRecord/', null=True, blank=True)
class Meta:
abstract = True
class Document(GenericRecord):
code = models.CharField(max_length=500, null=True, blank=True)
reference = models.CharField(max_length=500)
issue_date = models.DateField(auto_now=False, auto_now_add=False)
validation_date = models.DateField(auto_now=False, auto_now_add=False, null=True, blank=True)
def get_admin_url(self):
return reverse("admin:%s_%s_change" % (self._meta.app_label, self._meta.model_name), args=(self.id,))
def __unicode__(self):
if self.code:
return "%s-%s" % (self.code, self.document_title)
else:
return "--%s" % self.document_title
And this piece of code in views.py
def documents_list(request):
# Generate counts of some of the main objects
num_docs=Document.objects.all().count()
docs=Document.objects.all()
num_articles=Article.objects.all().count()
articles=Article.objects.all()
template='documents_management.html'
for object in docs:
object.fields = dict((field.name, field.value_to_string(object)) for field in object._meta.fields)
# Render the HTML template documents_management.html with the data in the context variable
return render(request,template, context={'docs':docs, 'num_docs':num_docs,'docs':docs, 'num_articles':num_articles, 'articles':articles})
In the template I'm trying to get a table with all the values, but for the related objects I get the primary key (of course).
Here is the code in my template:
<table class="w3-table-all">
{% for object in docs %}
{%if forloop.first %}
<tr>
{% for field, value in object.fields.iteritems %}
<th>{{ field }}</th>
{% endfor %}
</tr>
{%endif%}
{% endfor %}
{% for object in docs %}
{% for field, value in object.fields.iteritems %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
What I see in my browser
My question is, how can I get the object Category, Area etc... in order to get the category_type, area_type etc. value?
Thanks!
Here is an great example from the docs: https://docs.djangoproject.com/en/1.11/intro/tutorial03/#use-the-template-system
What you are searching for is the question.choice_set.all part.
UPDATE due to a hint of bad style
As mentioned by daniel you should ditch the Field.to_value_string method.
Since I am not a fan of implicit code I always recommend to code templates as explicit as possible, here would by my version of your template
<table class="w3-table-all">
{% for doc in docs %}
{% if forloop.first %}
<tr>
<th>Document Title</th>
<th>Category Type</th>
<th>Area Type</th>
<th>...</th>
</tr>
{% else %}
<tr>
<td>{{ doc.document_title }}</td>
<td>{{ doc.category.category_type }}</td>
<td>{{ doc.area.area_type }}</td>
<td>...</td>
</tr>
{% endif %}
{% endfor %}
</table>
What I changed:
only one for loop, you started with the if forloop.first you might also finish with the else case
refactored object to doc because objects is used often within django for model managers
add the fields explicit doc.area.area_type, this will prevent a new field in the model to also appear in the template but here I recommend an explicit over an implicit coding style
Also you can remove this from document_list:
for object in docs:
object.fields = dict((field.name, field.value_to_string(object)) for field in object._meta.fields)
The problem is in your use of Field.value_to_string. As the docstring on that method shows, this is for serialization, not for displaying values.
A much simpler and more effective way of doing this would be to use getattr, which gets the actual value; the template will then take care of converting those to a string, which in the case of the foreign keys will call the __unicode__ method of the related objects.
object.fields = dict((field.name, getattr(obj, field.name)) for field in object._meta.fields)