django - legacy DB and inner joins - django

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.

Related

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 3.2 - raw-SQL-Query with same table (Model)

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

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)

Show manytomany field in Django list view

I am trying to show the values of a manytomany field called teachers in a Django ListView.
At present my model looks like this:
class Classform(models.Model):
# Fields
name = models.CharField(max_length=255)
slug = extension_fields.AutoSlugField(populate_from='name', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
# Relationship Fields
school = models.ForeignKey('eduly.School', default=1)
teachers = models.ManyToManyField('eduly.Teacher', )
My ListView looks like this:
class ClassformListView(GroupRequiredMixin, ListView):
model = Classform
group_required = [u"school_admin"]
login_url = "/login/"
raise_exception = True
And my template for the list view looks like this:
<tr>
<td>{{object.pk}}</td>
<td>{{object}}</td>
<td>{{ object.name }}</td>
<td>{{ object.teachers }}</td>
<td>{{ object.created }}</td>
<td>{{ object.last_updated }}</td>
</tr>
When this code runs the displayed value for object.teachers is appname.Teacher.None
I have noticed that Django has created a table called appname_classform and also a table called 'appname_classform_teachers' (presumably for the manytomany field) but I am not sure how I need to change object.teachers to get the name of the teachers. The 'appname_classform_teachers' contains valid entries for teachers in the app name_teachers table.
Use object.teachers.all instead to get the actual queryset.
-- EDIT --
To render these in a custom way:
{% for objs_teacher in object.teachers.all %}
<p>{{ objs_teacher.first_name }}</p>
<p>{{ objs_teacher.last_name }}</p>
...
{% endfor %}
You can access the indevidual fields in the loop to make it look how you want.

Django check every objects of a query to see if have related objects and use this on template

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