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)
Related
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
We have migrated some database-tables from our productiv environment to the django ORM and auto sync this tables outside of django. → This works well so far, but we have troubles in django to connect this tables (Models) correctly to each other.
models.py
class SsdaSdgadr(models.Model):
sda_sdgid = models.ForeignKey(SsdgSendung, on_delete=models.CASCADE, blank=True, null=True)
sda_satid = models.CharField(max_length=4, blank=True, null=True)
sda_adrid = models.ForeignKey(SadrAdresse, on_delete=models.CASCADE, blank=True, null=True)
sda_ref = models.CharField(max_length=35, blank=True, null=True)
sda_termbis = models.DateField(blank=True, null=True)
sda_termvon = models.DateField(blank=True, null=True)
class Meta:
db_table = 'ssda_sdgadr'
unique_together = (('sda_sdgid', 'sda_satid'),)
class SsdgSendung(models.Model):
sdg_sdgid = models.CharField(primary_key=True, max_length=30)
sdg_konz = models.CharField(max_length=12, blank=True, null=True)
class Meta:
db_table = 'ssdg_sendung'
class SadrAdresse(models.Model):
adr_adrid = models.IntegerField(primary_key=True)
adr_name1 = models.CharField(max_length=35, blank=True, null=True)
adr_name2 = models.CharField(max_length=35, blank=True, null=True)
class Meta:
db_table = 'sadr_adresse'
Sample Data
SsdaSdgadr:
sdg_sdgid
sda_satid
sda_adrid
sda_ref
sda_termvon
sda_termbis
BL-1237781-BL-1
IV
169550
'00123/4539999'
''
''
BL-1237781-BL-1
SU
555555
''
01.12.2021
02.12.2021
BL-1237781-BL-1
CN
999999
'00123'
02.12.2021
13.12.2021
views.py
I used following raw SQL
Sendungen = SsdaSdgadr.objects.raw('''
SELECT
IV.id,
IV.sda_sdgid_id,
IV.sda_ref,
SU.id,
SU.sda_adrid_id as ABS,
SU.sda_termvon,
CN.id,
CN.sda_adrid_id as EMPF,
CN.sda_termbis
FROM
ssda_sdgadr IV
INNER JOIN ssdg_sendung on sdg_sdgid = IV.sda_sdgid_id
INNER JOIN ssda_sdgadr SU on SU.sda_sdgid_id = IV.sda_sdgid_id and SU.sda_satid="SU"
INNER JOIN ssda_sdgadr CN on CN.sda_sdgid_id = IV.sda_sdgid_id and CN.sda_satid="CN"
WHERE IV.sda_satid="IV"
GROUP BY
IV.id,
IV.sda_sdgid_id,
IV.sda_ref,
SU.id,
SU.sda_adrid_id,
SU.sda_termvon,
CN.id,
CN.sda_adrid_id,
CN.sda_termbis
ORDER BY
sdg_datum desc
''')
...
response = render(request, 'cust/home.html', {
'Sendungen': Sendungen,
})
return response
The result on the template works fine for the fields "SU.sda_termvon" & "CN.sda_termbis", but does not work for the field "sda_adrid" (→ Only the the result for IV.sda_adrid_id is displayed).
Template code
{% for la_item in Sendungen %}
<tr>
<td>{{ la_item.sda_sdgid.sdg_sdgid }}</td>
<td>{{ la_item.sda_ref }}</td> <!-- IV.sda_ref OKAY -->
<td>{{ la_item.sda_adrid.adr_adrid }}</td> <!-- is IV.sda_adrid NOT OKAY -->
<td>{{ la_item.sda_adrid.adr_adrid }}</td> <!-- is IV.sda_adrid NOT OKAY -->
<td>{{ la_item.sda_termvon|date }}</td> <!-- SU.sda_termvon OKAY -->
<td>{{ la_item.sda_termbis|date }}</td> <!-- CN.sda_termbis OKAY -->
</tr>
{% endfor %}
How can I access to the results "CN.sda_adrid_id" & "SU.sda_adrid_id" on template?
→ It look like that the ORM interprets the raw-SQL different than the database:
DB-Result & Desired result should look like this:
sda_sdgid_id
IV.sda_ref
SU.sda_adrid_id
CN.sda_adrid
SU.termvon
CN.termbis
BL-1237781-BL-1
1920192/4530210220/0881760357
555555
999999
01.12.2021
13.12.2021
My actual result look like this:
sda_sdgid_id
IV.sda_ref
IV.sda_adrid_id
IV.sda_adrid_id
SU.termvon
CN.termbis
BL-1237781-BL-1
1920192/4530210220/0881760357
169550
169550
01.12.2021
13.12.2021
I used this workaround (model property for "SsdaSdgadr"), which gave me the desired result:
models.py
class SsdaSdgadr(models.Model):
sda_sdgid = models.ForeignKey(SsdgSendung, on_delete=models.CASCADE, blank=True, null=True)
sda_satid = models.CharField(max_length=4, blank=True, null=True)
sda_adrid = models.ForeignKey(SadrAdresse, on_delete=models.CASCADE, blank=True, null=True)
sda_ref = models.CharField(max_length=35, blank=True, null=True)
sda_termbis = models.DateField(blank=True, null=True)
sda_termvon = models.DateField(blank=True, null=True)
class Meta:
db_table = 'ssda_sdgadr'
unique_together = (('sda_sdgid', 'sda_satid'),)
#property
def is_adr_su(self):
return SsdaSdgadr.objects.filter(sda_sdgid = self.sda_sdgid, sda_satid = "SU")
#property
def is_adr_cn(self):
return SsdaSdgadr.objects.filter(sda_sdgid = self.sda_sdgid, sda_satid = "CN")
views.py
Sendungen = SsdaSdgadr.objects.filter(Q(sda_satid__in=["IV"])).order_by('-sda_sdgid__sdg_datum')
...
response = render(request, 'cust/home.html', {
'Sendungen': Sendungen,
})
return response
Template code home.html
{% for la_item in Sendungen %}
<tr>
<td>{{ la_item.sda_sdgid.sdg_sdgid }}</td>
<td>{{ la_item.sda_ref }}</td> <!-- IV.sda_ref OKAY -->
{% for adr in la_item.is_adr_su %}
<td>{{ adr.sda_adrid.adr_adrid }}</td> <!-- SU.sda_adrid OKAY -->
<td>{{ adr.sda_termvon|date }}</td> <!-- SU.sda_termvon OKAY -->
{% endfor %}
{% for adr in la_item.is_adr_cn %}
<td>{{ adr.sda_adrid.adr_adrid }}</td> <!-- CN.sda_adrid OKAY -->
<td>{{ adr.sda_termbis|date }}</td> <!-- CN.sda_termbis OKAY -->
{% endfor %}
</tr>
{% endfor %}
I have a template with a table, and there I have all the objects on a query. Each object can have related objects or not. Assuming this, what I need to do is, for each object check if have or not that related object. If not in the table I have a field to put a link to create a related object, but if have show a icon to see this object.
I can do with the one of the "parent" object but I don't know how to do if I have more than one object in the query.
Models to check:
class Accident(models.Model):
employee = models.ForeignKey(Employee)
place = models.IntegerField(choices=ACCIDENT_PLACE, default=1)
detail = models.CharField(max_length=255)
clinic = models.ForeignKey(Clinic)
is_urgency = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User,
related_name='accidents_created_by',
editable=False,
blank=True,
null=True
)
modified_by = models.ForeignKey(User,
related_name='accidents_modified_by',
editable=False,
blank=True,
null=True
)
class Meta:
verbose_name = "accidente"
verbose_name_plural = "accidentes"
def __str__(self):
return str(self.id)
class AccidentCertificate(models.Model):
accident = models.ForeignKey(Accident)
diagnostic = models.CharField(max_length=150)
return_day = models.DateField()
notes = models.CharField(max_length=255)
medication = models.CharField(max_length=255)
doctor = models.ForeignKey(Doctor)
presented = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User,
related_name='acc_certificates_created_by',
editable=False,
blank=True,
null=True
)
modified_by = models.ForeignKey(User,
related_name='acc_certificates_modified_by',
editable=False,
blank=True,
null=True
)
class Meta:
verbose_name = "certificado de accidente"
verbose_name_plural = "certificados de accidente"
ordering = ["-id"]
def __str__(self):
return str(self.id)
this is my view (to check only one object that i already know that have 1 related object)
class EmployeeDetailView(LoginRequiredMixin, DetailView):
# Chequeamos que el usuario se encuentre logeado
login_url = reverse_lazy('users:login')
model = Employee
template_name = 'employees/detail.html'
pk_url_kwarg = 'employee_id'
def get_context_data(self, **kwargs):
context_object_name = 'employee'
context = super(EmployeeDetailView, self).get_context_data(**kwargs)
employee = context['employee']
context['cuil'] = employee.cuil[:2]+'-'+employee.cuil[2:10]+'-'+employee.cuil[-1:]
# Tomamos los accidentes correspondientes al empleado
# y los pasamos al contexto
employee_accidents = Accident.objects.filter(employee=employee)
context['accidents'] = employee_accidents
# Tomamos el certificado del accidente si existe
accident_certificate = AccidentCertificate.objects.get(accident=employee_accidents)
return context
and in the template
<table class="table table-striped">
<thead>
<tr>
<th>ID Acc.</th>
<th>Fecha</th>
<th>Cant. Días</th>
<th>Locación</th>
<th>Detalle</th>
<th>Clinica</th>
<th>Urgencia</th>
<th>Cargado por</th>
<th>Certificado</th>
<th>Segimiento</th>
</tr>
</thead>
<tbody>
{% for a in accidents %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.created|date }}</td>
<td>-</td>
<td>{{ a.get_place_display }}</td>
<td>{{ a.detail }}</td>
<td>{{ a.clinic }}</td>
<td>
{% if a.is_urgency %}
Si
{% else %}
No
{% endif %}
</td>
<td>{{ a.created_by }}</td>
<td>{% bootstrap_icon "search" %}</td>
<td>{% bootstrap_icon "search" %}</td>
</tr>
{% empty %}
<p class="text-center">
<strong>NO HAY REGISTROS</strong>
</p>
{% endfor %}
</tbody>
</table>
Well in sintesis I need to take every accidents that correspond to an employee, and for each accident check if this have an AccidentCertificate, if it have put the link in the table to see the certificate, and if not put the link to create the certificate.
You can use a count annotation to add the number of related certificates to each accident, then use that number in an if statement in the template.
from django.db.models import Count
...
employee_accidents = Accident.objects.filter(employee=employee).annotate(certificate_count=Count('accidentcertificate'))
...
{% for a in accidents %}
...
{% if a.certificate_count == 0 %}
Add new certificate
{% endif %}
{% endfor %}
I have the following models -
class Schmst(models.Model):
schmst_proddt = models.DateTimeField(primary_key=True)
class Meta:
managed = False
db_table = 'schmst'
class Owner(models.Model):
owner_id = models.IntegerField(primary_key=True)
owner_name = models.CharField(max_length=30, blank=True)
class Meta:
managed = False
db_table = 'owner'
class Jobmst(models.Model):
jobmst_id = models.IntegerField(primary_key=True, db_column='jobmst_id', to_column='jobmst_id')
jobmst_type = models.SmallIntegerField()
jobmst_name = models.TextField(blank=True)
class Meta:
managed = False
db_table = 'jobmst'
class Jobrun(models.Model):
jobrun_id = models.IntegerField(primary_key=True)
jobmst_id = models.ForeignKey(Jobmst, db_column='jobmst_id', to_field='jobmst_id')
jobmst_type = models.SmallIntegerField(blank=True, null=True)
jobrun_proddt = models.ForeignKey(Schmst, db_column='jobrun_proddt', to_field='schmst_proddt')
jobrun_owner = models.ForeignKey(Owner, db_column='jobrun_owner', to_field='owner_id')
class Meta:
managed = False
db_table = 'jobrun'
From there I have a view that doesn't seem to be doing any joining.
def hungjobs(request):
template_vars['jobrun'] = Jobrun.objects.db_manager('Admiral').prefetch_related('jobmst_id__owner_id').filter(jobrun_status=51, jobrun_duration__gt=1800, jobmst_type__in=[2, 6])
t = get_template('queries\HungJobs.html')
c = Context(template_vars)
return HttpResponse(t.render(c), mimetype="text/html")
The results from there I want to parse into my template below -
<table border="1">
<tr>
<td>Owner</td>
<td>Production Date</td>
<td>Job ID</td>
<td>Duration</td>
<td>Job Name</td>
</tr>
{% for jobrun in jobrun %}
<tr>
<td>{{ jobrun.owner_name }}</td>
<td>{{ jobrun.jobrun_proddt|date:"M d, Y" }}</td>
<td>{{ jobrun.jobrun_id }}</td>
<td>{{ jobrun.jobrun_duration }}</td>
<td>{{ jobrun.jobmst_name }}</td>
</tr>
{% endfor %}
</table>
Currently only the jobrun_id and jobrun_duration are loading into the template because the values are in the model I'm directly querying. The foreignkey relationships however don't seem to be working and I'm unsure why as from everything I've checked they're designed properly.
I haven't ran your code but I see a few mistakes:
For loop variable name should be changed [or you can change the template variable name] from jobrun to jobruns. It's not a good practice to reuse variable names this way.
You need to specify what field of the foreign key needs to be printed in the template. Something like:
{{ jobrun.jobrun_proddt.schmst_proddt|date:"M d, Y" }}
for the date. As it stands right now, you are returning the objects and not a specific field of the foreign key objects.
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>