For loop in template django with prefetch_related - django

I got an issue when trying to access values from other models by using prefetch_related
My model:
class testimport(models.Model):
id=models.AutoField(primary_key=True)
so_hd=models.CharField( max_length=50, unique=True)
ten_kh=models.CharField( max_length=500)
tien_dong=models.IntegerField(blank=True, null=True)
created_at=models.DateTimeField(auto_now_add=True)
objects=models.Manager()
def get_absolute_url(self):
return "/chi_tiet_hop_dong/%s/" % self.so_hd
class report(models.Model):
id=models.AutoField(primary_key=True)
so_hd=models.ForeignKey(testimport, on_delete=models.DO_NOTHING, to_field="so_hd")
nhan_vien=models.ForeignKey(Callers, on_delete=models.DO_NOTHING, null=True, blank= True, to_field="admin_id")
noi_dung=models.TextField()
My views:
....
get_contract_detail=testimport.objects.filter(so_hd__in=get_user).order_by("id").prefetch_related().values()
contract=get_contract_detail.filter(so_hd=so_hd).all()
return render(request, "caller_template/contract_detail.html", {"contract":contract,"the_next":the_next,"the_prev":the_prev, "so_hd":so_hd,"form":form,"form1":form1})
If I try to print out the content by values, it is ok:
print(get_contract_detail.filter(so_hd=so_hd).values("so_hd","report__noi_dung"))
In my template:
{% for report in contract %}
{% for content in report.so_hd.all%}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{content.noi_dung}}</td>
</tr>
{% endfor %}
{% endfor %}
There is no content in cells. How can I show the content
Please help

The reason this does not work is because of the use of .values(…) [Django-doc]. Furthermore you did not specify a related_name=… parameter [Django-doc], so that means that you access the reports with .report_set.all():
contract = testimport.objects.filter(
so_hd__in=get_user, so_hd=so_hd
).order_by('id').prefetch_related() # no .values()
context = {
'contract': contract,
'the_next': the_next,
'the_prev': the_prev,
'so_hd': so_hd,
'form': form,
'form1':form1
}
return render(request, 'caller_template/contract_detail.html', context)
and in the template render with .report_set.all:
{% for report in contract %}
{% for content in report.report_set.all %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ content.noi_dung }}</td>
</tr>
{% endfor %}
{% endfor %}

Related

Django render many to many attributes after query, display None

I am using slug to query the model, and render result in HTML.
The code is unable to render actual name of region, it just return None
Model
class Region(models.Model):
name = models.CharField(blank=False, unique=True)
def __str__(self):
return self.name
class Theme(models.Model):
name = models.CharField(blank=False, unique=True)
slug = models.SlugField(default="", null=False)
def __str__(self):
return self.name
class ETF(models.Model):
ticker = models.CharField(max_length=6, blank=False, db_index=True, unique=True)
full_name = models.CharField(max_length=200, blank=False)
# many to many
region = models.ManyToManyField(Region)
theme = models.ManyToManyField(Theme)
views.py
def theme_etf(request, slug): # render ETFs with theme filter
filtered_results = ETF.objects.filter(theme__slug=slug)
return render(request, "etf/list_etf.html", {
"ETFs": filtered_results
})
Part of list_etf.html
{% for ETF in ETFs %}
<tr>
<td>{{ ETF.ticker }}</td>
<td>{{ ETF.full_name }}</td>
<td>{{ ETF.region.name }}</td> # What should I use in this line
</tr>
{% endfor %}
The code is unable to render actual name of region, it just return None
Result
Ticker, Name, Region
ARKF, ARK Fintech Innovation ETF, None
ARKK, ARK Innovation ETF, None
KEJI, Global X China Innovation, None
I would like to have this:
Ticker, Name, Region
ARKF, ARK Fintech Innovation ETF, Global
ARKK, ARK Innovation ETF, Global
KEJI, Global X China Innovation, China
I have the information in the database. I have checked it in admin.
Can an ETF have multiple regions as implied by your database design? If it does not I would suggest you use ForeignKey instead.
You are accessing the region field as if it were a ForeignKey.
In your database design you need to iterate over the objects saved in the ManyToManyField using .all.
{% for ETF in ETFs %}
<tr>
<td>{{ ETF.ticker }}</td>
<td>{{ ETF.full_name }}</td>
<td>{% for region in ETF.region.all %}{{ region.name }}{%endfor%}</td>
</tr>
{% endfor %}
Because you have many-to-many relationship, you cannot simply have single values. So, you have to list values.
{% for ETF in ETFs %}
<tr>
<td>{{ ETF.ticker }}</td>
<td>{{ ETF.full_name }}</td>
<td>
<ol>
{% for region in ETF.region %}
<li>{{region.name}}</li>
{% endfor %}
</ol>
</td>
</tr>
{% endfor %}

django user fields shown empty in template

cannot access fields in templates
model.py:
class DSS(models.Model):
title = models.CharField(max_length=255, null=True, blank=True, verbose_name='عنوان')
usr = models.ForeignKey(User, related_name='owner', verbose_name='کاربر')
view.py:
def state(request):
result = DSS.objects.values('usr').order_by('usr').annotate(count=Count('usr'))
context = {'result': result,}
return render(request, 'state.html', context)
my template:
<tr>
<td>{{ item.usr }}{{ item.usr.get_username}}{{ item.usr.username}}{{ item.usr.get_full_name}}</td>
<td>{% with item.usr.get_username as usrnm %}
{{ item.usr.get_full_name|default:usrnm }}
{% endwith %}</td>
<td>{{ item.usr.first_name }} {{ item.usr.lastname }}</td>
<td>{{ item.owner.first_name }}</td>
<td>{{ item.count }}</td>
</tr>
{{ item.count }} work well and {{ item.usr }} just show user id, but I need to display username however none of this tries worked!
Instead of values(), try to send the actual queryset. And to reduce DB hits, you can use select_related(). For example:
result = DSS.objects.select_related('usr').order_by('usr')
Also .annotate(count=Count('usr')) will not work properly. It will show 1 for each item of queryset. Instead, try aggregating.
def state(request):
result = DSS.objects.select_related('usr').order_by('usr')
user_count = result.aggregate(u_count=Count('usr')).get('u_count')
context = {'result': result, 'user_count': user_count}
return render(request, 'state.html', context)
And render it in template:
{{ user_count }}
Instead of
result = DSS.objects.values('usr').order_by('usr').annotate(count=Count('usr'))
Try
result = DSS.objects.values('usr', 'usr__username').order_by('usr').annotate(count=Count('usr'))
And in html
{{ item.usr__username }}
Try to add the __str__ method in the user model.
def __str__(self):
return self.first_name + " " + self.last_name
# use the fields you have in your user model, mine was first_name and last_name

Select data from drop-down list and save it to database in Django

I am a newbie in Django. I want to show the food_status in drop-down list options, therefore the chef can select one of them, change it, and update it into database. It can be updated into database, but i am not sure how to display the drop-down list on template based on the food_status that I have in models.py.
Anyone know how to do it?
models.py
class OrderItem(models.Model):
Table_No = models.IntegerField(blank=False)
FoodId = models.TextField()
Item = models.TextField()
Qty = models.DecimalField(max_digits=5, decimal_places=0)
Price = models.DecimalField(max_digits=10, decimal_places=2)
TotalPrice = models.TextField()
Note = models.TextField(max_length=100, null=True)
OrderId = models.TextField(max_length=5, null=True)
FoodStatus = (
('1', 'Has been ordered'),
('2', 'cooked'),
('3', 'ready to be served'),
('4', 'done'),
)
food_status = models.CharField(max_length=50, choices=FoodStatus)
views.py
def see_order(request):
if request.method == "POST":
OrderId = request.POST.get("OrderId")
customerOrder = OrderItem(OrderId=OrderId)
so = OrderItem.objects.filter(OrderId=OrderId)
return render(request, 'restaurants/see_order.html', {'so': so})
else:
return render(request, 'restaurants/customer_page.html')
see_order.html
<form action="#" method="post">
<style>
table, th, td {
border: 1px solid black;
table-layout: fixed ;
height: "2000" ;
width: "2000" ;
}
</style>
{% csrf_token %}
{% for order in so %}
<table>
<tr>
<th>Table Number</th>
<th>Item</th>
<th>Quantity</th>
<th>Status</th>
<th>Order Id</th>
</tr>
<tr>
<td>{{ order.Table_No }}</td>
<td>{{ order.Item }}</td>
<td>{{ order.Qty }}</td>
<td>{{ order.food_status }}</td>
<td>{{ order.OrderId }}</td>
</tr>
{% endfor %}
</table>
<br><input action="action" onclick="window.history.go(-1); return false;" type="button" value="Back"></br>
</form>
The kitchen_page template should show the drop-down list, then the chef can choose the food_status from that drop-down list, click save button, and update the database.
You can render choices using {% for %} loop and FoodStatus list of choices like this:
<td>
{{ order.get_food_status_display }}
<select name="food_status">
{% for id, choice in order.FoodStatus %}
<option value="{{ id }}"{% if order.food_status == id %} selected="selected"{% endif %}>{{ choice }}</option>
{% endfor %}
</select>
</td>
You can display actual status text (instead of id), using get_FOO_display method.
Added {% if %} tag to preselect correct option.
Consider switching to Forms so it can handle rendering fields automatically.(!!!)
Consider switching food_status to IntegerField instead. Provide default attribute, so it will always be one of the choices, even if not specified.
Try using choices attribute of Django fields https://docs.djangoproject.com/en/2.0/ref/models/fields/#choices

Display a form and the output on the same page

This code will display the form. I can input data, submit the data and the data then displays along with the previous input data from the mySQL DB table where the dat is written, but when the data displays the input form goes away (all expect the submit button that is). I've come across this subject here, but could never quite find the answer that worked for me.
**`models.py`**
class UnitPool(models.Model):
# rack = models.ForeignKey(Rack)
# platform = models.ForeignKey(Group)
location = models.CharField(max_length=10, choices=LAB, default='Choose', blank=False)
rack = models.CharField(max_length=10, choices=RACKS, default='Choose', blank=False)
platform = models.CharField(max_length=10, choices = PLATFORM, default='Choose',blank=False)
unit_HW_Serial = models.CharField(max_length=20, blank=False, null=False)
unit_SW_Serial = models.CharField(max_length=20, blank=False, null=False)
unit_SKU = models.CharField(max_length=20, blank=False, null=False)
comments = models.CharField(max_length=64, blank=True, null=True, default='')
def __unicode__(self): # __unicode__ on Python 2
return '%s %s %s %s %s %s' % (self.rack,
self.platform,
self.unit_HW_Serial,
self.unit_SW_Serial,
self.unit_SKU,
self.comments)
class UUTForm(ModelForm):
class Meta:
model = UnitPool
widgets = {
'comments': TextInput(attrs={'size': 10}),
}
fields = ['location','rack', 'platform','unit_HW_Serial','unit_SW_Serial','unit_SKU','comments']
**forms.html**
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<div class='row'>
<div class='col-md-2'>
{% if title %}
<h1 class='{% if title_align_center %}text-align-center{% endif %}'>{{ title }}</h1>
{% endif %}
<form method='POST' action=''>{% csrf_token %}
{{ form|crispy }}
<input class='btn btn-primary' type='submit' value='Add Unit' />
</form>
</div>
</div>
</div>
{% if queryset %}
{% if rack != '' %}
<div class="container">
<div class="row">
<div class='col-md-8 col-md-offset-3'>
<h1>Unit Data Entered</h1>
<table class='table'>
<td><b>Item</b></td>
<td><b>Location</b></td>
<td><b>Rack#</b></td>
<td><b>Platform</b></td>
<td><b>HW SN</b></td>
<td><b>SW SN</b></td>
<td><b>SKU</b></td>
<td><b>Comment</b></td>
{% for instance in queryset %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ instance.location }}</td>
<td>{{ instance.rack }}</td>
<td>{{ instance.platform }}</td>
<td>{{ instance.unit_HW_Serial }}</td>
<td>{{ instance.unit_SW_Serial }}</td>
<td>{{ instance.unit_SKU }}</td>
<td>{{ instance.comments }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endblock %}
**views.py**
from django.conf import settings
from django.shortcuts import render
from .models import UnitPool, UUTForm
def labunits(request):
title = 'Enter Info'
form = UUTForm(request.POST or None)
context = {
"title": title,
"form": form
}
if form.is_valid():
instance = form.save(commit=False)
instance.save()
queryset = UnitPool.objects.all().order_by('rack','platform')
context = {
"queryset": queryset
}
return render(request, "labunits/forms.html", context)
You need to pass the form in the context after calling .is_valid() as #Daniel also mentioned.
Since you are not passing the form in the context again after calling the .is_valid() function, the form does not get displayed again in the template.
So, when you are resetting the context, you need to pass the form also.
def labunits(request):
title = 'Enter Info'
form = UUTForm(request.POST or None)
context = {
"title": title,
"form": form
}
if form.is_valid():
instance = form.save(commit=False)
instance.save()
queryset = UnitPool.objects.all().order_by('rack','platform')
context = {
"queryset": queryset,
"form" : form # pass the form in the context
}
return render(request, "labunits/forms.html", context)

Django model cross reference in templatre

Ok So my mind is going to mush...
I have 2 models. One is a card location and the other holds card types. I've got a view and template which display's the cards in a specific chassis. What I can't seem to get to work is the foreign key reference. I want to display the CardType.sName in the template.
I'm certain i've just done something stupid ...
Models.py:
class CardLocation(models.Model):
chassis = models.ForeignKey(Chassis)
slot = models.CharField(max_length=20)
slot_sub = models.CharField(max_length=20)
CardType = models.ForeignKey(CardType)
PartNum = models.CharField(max_length=200)
ProdID = models.CharField(max_length=200)
versID = models.CharField(max_length=200)
serialNum = models.CharField(max_length=200)
cleiCode = models.CharField(max_length=200)
lastSeen = models.DateTimeField()
isActive = models.BooleanField(default=0)
def __unicode__(self):
return self.slot
class CardType(models.Model):
sName = models.CharField(max_length=5)
lName = models.CharField(max_length=200)
description = models.CharField(max_length=200)
def __unicode__(self):
return self.sName
views.py
class DetailView(generic.ListView):
model = CardLocation
template_name = 'chassis/detail.html'
context_object_name = 'cardLoc'
def get_queryset(self):
#chassis_id = get_object_or_404(CardLocation, chassis_id__iexact=self.args[0])
chassis_id = self.args[0]
return CardLocation.objects.filter(chassis_id=chassis_id)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(DetailView, self).get_context_data(**kwargs)
# Add in the
context['chassisQ'] = Chassis.objects.get(id=self.args[0])
#context['CardType'] = CardType.objects.order_by()
return context
detail.html
{% load staticfiles %}
<h2>
<table>
<tr><td>Name:</td><td>{{ chassisQ.name }}<td></tr>
<tr><td>Owner:</td><td>{{ chassisQ.owner }}<td></tr>
<tr><td>ip Adress:</td><td>{{ chassisQ.ipAddr }}<td></tr>
<tr><td>Last updated:</td><td>{{ chassisQ.lastSeen }}<td></tr>
</table>
</h2>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% if cardLoc %}
<table border=1>
<tr><td>slot</td><td>Type</td><td>Part Number</td><td>Product ID/</td><td>Version ID</td><td>Serial Num</td><td>CLEI code</td></tr>
{% for card in cardLoc %}
<tr>
<td align="right">{{ card.slot }}</td>
<td>Type {{ card.cardtype__set.all.sName }} </td> <!-- DISPLAY sName HERE -->
<td>{{ card.PartNum }}</td>
<td align="right">{{ card.ProdID }}/</td>
<td align="left">{{ card.versID }}</td>
<td>{{ card.serialNum }}</td>
<td>{{ card.cleiCode }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>No cards are available...</p>
{% endif %}
A Card has numerous CardTypes (as it's a ForeignKey relationship), not just one. You have:
<td>Type {{ card.cardtype__set.all.sName }} </td>
You need to loop through all the CardTypes related to the Card:
{% for card in cardLoc %}
...
{% for cardtype in card.cardtype__set.all %}
<td>Type {{ cardtype.sName }}</td>
{% endfor %}
...
{% endfor %}