Django 3.2 - raw-SQL-Query with same table (Model) - django

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

Related

How not to display Django foreign key object source in table

I want to display date in table which is foreign key in this case and when I do this as result I see the date with information that it is object of different table. Which I don't want.
I would appreciate help with this.
class Factclaimcases(models.Model):
idfactclaimcase = models.IntegerField(db_column='IdFactClaimCase', primary_key=True) # Field name made lowercase.
idtechnican = models.ForeignKey(Dimtechnican, models.DO_NOTHING, db_column='IdTechnican') # Field name made lowercase.
thedate = models.ForeignKey(Dimdate, models.DO_NOTHING, db_column='TheDate') # Field name made lowercase.
description = models.CharField(db_column='Description', max_length=50) # Field name made lowercase.
manufacturedef = models.TextField(db_column='ManufactureDef', blank=True, null=True) # Field name made lowercase. This field type is a guess.
doc = models.BinaryField(db_column='Doc', blank=True, null=True) # Field name made lowercase.
<div class="container">
<table>
{% for item in query_results %}
<tr>
<td>{{ item.idfactclaimcase }}</td>
<td>{{ item.thedate }}</td>
<td>{{ item.description }}</td>
</tr>
{% endfor %}
</table>
</div>
def index(request):
query_results = Factclaimcases.objects.all()
context = {
'query_results': query_results,
}
return render(request, 'index.html', context)
class Dimdate(models.Model):
thedate = models.DateField(db_column='TheDate', primary_key=True) # Field name made lowercase.
theday = models.IntegerField(db_column='TheDay', blank=True, null=True) # Field name made lowercase.
thedayname = models.CharField(db_column='TheDayName', max_length=30, blank=True, null=True) # Field name made lowercase.
theweek = models.IntegerField(db_column='TheWeek', blank=True, null=True) # Field name made lowercase.
theisoweek = models.IntegerField(db_column='TheISOWeek', blank=True, null=True) # Field name made lowercase.
thedayofweek = models.IntegerField(db_column='TheDayOfWeek', blank=True, null=True) # Field name made lowercase.
themonth = models.IntegerField(db_column='TheMonth', blank=True, null=True) # Field name made lowercase.
themonthname = models.CharField(db_column='TheMonthName', max_length=30, blank=True, null=True) # Field name made lowercase.
thequarter = models.IntegerField(db_column='TheQuarter', blank=True, null=True) # Field name made lowercase.
theyear = models.IntegerField(db_column='TheYear', blank=True, null=True) # Field name made lowercase.
thefirstofmonth = models.DateField(db_column='TheFirstOfMonth', blank=True, null=True) # Field name made lowercase.
thelastofyear = models.DateField(db_column='TheLastOfYear', blank=True, null=True) # Field name made lowercase.
thedayofyear = models.IntegerField(db_column='TheDayOfYear', blank=True, null=True) # Field name made lowercase.
You render it by accessing the field you want to render, so:
<div class="container">
<table>
{% for item in query_results %}
<tr>
<td>{{ item.idfactclaimcase }}</td>
<td>{{ item.thedate.thedate }}</td>
<td>{{ item.description }}</td>
</tr>
{% endfor %}
</table>
</div>
You can use the |date template filter [Django-doc] to specify how to render the date, for example:
<div class="container">
<table>
{% for item in query_results %}
<tr>
<td>{{ item.idfactclaimcase }}</td>
<td>{{ item.thedate.thedate|date:"Y-m-d" }}</td>
<td>{{ item.description }}</td>
</tr>
{% endfor %}
</table>
</div>
In your view, you can select the Dimdate columns in the same query with .select_related(…) [Django-doc]:
def index(request):
query_results = Factclaimcases.objects.select_related('thedate')
context = {
'query_results': query_results,
}
return render(request, 'index.html', context)

foriegn key object not iterable in template

I have basic models for a section, subsection and clause. 1 section can hold multiple subsections. Each subsection can hold multiple clauses. The models look like:
**models.py**
class Clause(models.Model):
number = models.CharField(max_length=8, unique=True)
requirements = models.TextField(max_length=2000, unique=False, blank=True, null=True)
documentation = models.TextField(max_length=2000, unique=False, blank=True, null=True)
class Subsection(models.Model):
number = models.CharField(max_length=5, unique=True)
name = models.CharField(max_length=150, unique=False)
descriptor = models.TextField(max_length=2000, unique=False, blank=True, null=True)
clause = models.ForeignKey(Clause, on_delete=models.DO_NOTHING, related_name="clause")
class Section(models.Model):
number = models.CharField(max_length=2, unique=True)
name = models.CharField(max_length=150, unique=False)
descriptor = models.TextField(max_length=2000, unique=False, blank=True, null=True)
subsection = models.ForeignKey(Subsection, on_delete=models.DO_NOTHING, related_name="subsection")
basic view function to call the desired section:
**views.py**
def main(request):
form = MainSearchForm()
user = request.user
sections = []
show_results = True
if 'query' in request.GET:
show_results = True
query = request.GET['query'].strip()
if len(query) <= 2:
sections = Section.objects.filter(number__iexact=query)
if sections:
records = sections
tpl = "display_console.html"
context = {'user': user, 'records': records, 'form': form}
return render(request, tpl, context)
else:
tpl = "main.html"
context = {'user': user, 'form': form}
return render(request, tpl, context)
unfortunately, I can't get my template to return my subsection data. The following returns a 'Subsection' object is not iterable error:
**template**
<table class="section_tb">
{% if records %}
{% for record in records %}
<tr>
<td>{{ record.number }}</td><td>{{ record.name }}</td>
</tr>
{% for item in record.subsection %}
<tr>
<td>{{ item.number }}</td><td>{{ item.name }}</td>
</tr>
<tr>
<td colspan=2>{{ item.descriptor }}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
{% else %}
{% endif %}
substituting:
{% for item in record.subsection.all %}
for:
{% for item in record.subsection %}
removes the error message, but doesn't return any data. Is there something obvious I'm doing wrong?
This is because Section can have only one Subsection.
So you can access the subsection with just {{record.subsection}} so no forloop needed here.
As a tip remember when you usea one to many, the one is where the foreign key is defined.
The model that store the foreign key will always store only one foreign key.
If you want to access the many foreign keys from the other side use the model_name_in_lowercase_set or define a related name in models.ForeignKey(..., related_name="something") then you can call something_set

Django -Help displaying content in nested for loop

I have a Requisition which may have multiple lines. So to implement this I included a unique_together constraint on two fields on the RequisitionLine model which one of the fields is a FK to Requisition . So naturally to pull all the lines of a requisition I would query the RequisitionLine table where the FK = the id of the Requisition model, then iterate over all the sequences to grab all the lines.
My goal is to display the header number with the lines of that requisition under the header in the template but am struggling to accomplish this. I have tried to iterate over the queryset but the code i am posting below is my most recent attempt trying pass lists to the template which is also not working. Right now each header is showing all the lines. Any help would be appreciated.
Models.py
class Requisition(models.Model):
username = models.ForeignKey(
'users.CustomUser', on_delete=models.CASCADE, related_name='req_user')
signature = models.CharField(max_length=10, blank=True, null=True)
class RequisitionLine(models.Model):
parent_req = models.ForeignKey('Requisition', on_delete=models.CASCADE, related_name='par_req_line' )
sequence = models.PositiveIntegerField()
item_code = models.ForeignKey(
'items.ItemMaster', on_delete=models.CASCADE, related_name='req_item', blank=True, null=True)
description = models.CharField(max_length=50, blank=True)
extra_information = models.TextField(blank=True)
quantity = models.PositiveIntegerField(blank=True, default=0,null=True)
price = models.DecimalField(max_digits=19, decimal_places=2, blank=True, default=0.00,null=True)
purchase_order = models.CharField(max_length=9, blank=True,null=True)
po_line = models.PositiveSmallIntegerField(blank=True,null=True)
req_delivery_date = models.DateField(blank=True,null=True)
act_delivar_date = models.DateField(blank=True, null=True)
status = models.ForeignKey('RequisitionStatus', related_name='req_status', on_delete=models.CASCADE, blank=True, null=True)
assistance = models.ForeignKey('users.UserRoles', related_name='req_assist', blank=True, null=True, on_delete=models.CASCADE, limit_choices_to= ~Q(role='Requestor'))
catagory = models.ForeignKey('items.ItemCatagory', on_delete=models.CASCADE, related_name='line_cat', blank=True, null=True)
notes = models.TextField(blank=True)
class Meta:
unique_together = ('parent_req','sequence')
Views.py
def pending_action(request):
user = CustomUser.objects.get(username=request.user)
user_req_headers = Requisition.objects.filter(username=user)
complete_status = RequisitionStatus.objects.get(status='Completed')
req_line_list = []
for req_header in user_req_headers:
req_lines = RequisitionLine.objects.filter(Q(parent_req = req_header) & ~Q(status=complete_status))
req_line_list.append(req_lines)
return render(request, 'req/pending_action.html', {'user_req_headers':user_req_headers,'req_line_list':req_line_list})
pending_action.html
{% for header in user_req_headers %}
<h3>{{header}}</h3>
{% for req_line in req_line_list %}
{% for req in req_line %}
<table>
{% if forloop.first %}
<tr>
<th>description</th>
<th>catagory</th>
</tr>
{% endif %}
<tr>
<!-- FOR LOOP HERE TO ITERATE OF LIST OF QUERYSETS-->
<td>{{ req }}</td>
</tr>
</table>
{% endfor %}
{% endfor %}
{% endfor %}
I solved this problem by creating a queryset of the header and using a reverse relationship to capture the lines associated with each header
<table class="table">
{% for req_header in req_header_list %}
<tr>
<ul>{{ req_header }}
{% for line in req_header.par_req_line.all %}
<li>{{line}}</li>
{% endfor %}
</ul>
</tr>
{% endfor %}
</table>

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)

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