Django template object type - django

Alright, here's my situation. I've got an array of generic objects that I'm iterating over in a django template. Those objects have a number of subclasses and I want to figure out in the template which subclass I'm dealing with. Is this possible? Advisable?
The code might look something along the lines of (where the if statements include some imaginary syntax):
<table>
<tr>
<th>name</th>
<th>home</th>
</tr>
{% for beer in fridge %}
<tr>
<td>
{{ beer.name }}
</td>
<td>
{% if beer is instance of domestic %}US of A{% endif %}
{% if beer is instance of import %}Somewhere else{% endif %}
</td>
</tr>
{% endfor %}
</table>

This is an old question, but FWIW you can do this with a template filter.
#register.filter
def classname(obj):
return obj.__class__.__name__
Then in your template you can do:
{% with beer|classname as modelclass %}
{% if modelclass == "Domestic" %}US of A
{% elif modelclass == "Import" %}Somewhere else
{% endif %}
{% endwith %}

You'll have to do it via some sort of method. Why not just write a method like display_location() or something on the model itself and have it return the string which gets rendered there? Then you could just put {{ beer.display_location }} in your template.
Or if you want to go really crazy, write a custom template tag that does what you want, but that's much more work.

Related

Get Data Problem with Foreignkey Models QuerySet (Django)

I am making django practising. I found a repo and edited to myself. When i came to the get data from models with foreignkey, i get query instead of data. I think my function is a little bit spagetti or my template file.
Full repo is here https://github.com/eseymenler/demo2
Here is the output of my codes. First red square is query, but i want second red square datas.
Hasta Adı: {{ patient.name }}
Hastanın Sağlık Problemi: {{ prob }}
Hastanın Boyu: {{ vital }}
Hastanın Sigara Kullanım Durumu: {{ social }}
First data {{ patient.name }} is very good for me. Thats what i want.
But when i get write {{ prob.problem }} it gives me nothing. So where is my fault.
But also when i make for loop like this, i get data which i want. So how can i fix this.
{% for y in prob %}
{{ y.problem }}
{% endfor %}
And my views.py
#login_required()
def patienttumbilgiListView(request, id):
patient = Patient.objects.get(aadhaarId = id)
prob = ProblemList.objects.filter(patient = patient)
vital = VitalSign.objects.filter(patient = patient)
social = SocialHistory.objects.filter(patient = patient)
return render(
request, 'patient_records/patient-problem-tum.html',
context={'prob': prob, 'vital': vital, 'social': social, 'patient': patient })
and my template file
{% extends 'base.html' %}
{% load static %}
{% load bootstrap4 %}
{% load i18n %}
{% block title %}problem-list-view{% endblock title %}
{% block content %}
<div class="container">
Hasta Adı: {{ patient.name }}</br>
Hastanın Sağlık Problemi: {{ prob }}<br>
Hastanın Boyu: {{ vital }}<br>
Hastanın Sigara Kullanım Durumu: {{ social }} <br></div>
<br>
<br>
<div class="container">
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<thead>
<tr>
<th class="tg-0lax">Hasta Adı:</th>
<th class="tg-0lax">{{ patient.name }}</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-0lax">Hastanın Sağlık Problemi:</td>
<td class="tg-0lax">{% for y in prob %}<br> <br> {{ y.problem }}<br> <br> <br>{% endfor %}</td>
</tr>
<tr>
<td class="tg-0lax">Hastanın Boyu:</td>
<td class="tg-0lax">{% for x in vital %}<br> <br> {{ x.height }}<br> <br> <br>{% endfor %}</td>
</tr>
<tr>
<td class="tg-0lax">Sigara Kullanımı:</td>
<td class="tg-0lax">{% for item in social %}<br> <br><br> {{ item.tobacco_smoking_status }}<br> <br> <br>{% endfor %}</td>
</tr>
</tbody>
</table>
</div>
<br>
<br>
{% endblock %}
Roughly What You Had
So your code is:
#login_required()
def patienttumbilgiListView(request, id):
patient = Patient.objects.get(aadhaarId = id)
prob = ProblemList.objects.filter(patient = patient)
vital = VitalSign.objects.filter(patient = patient)
social = SocialHistory.objects.filter(patient = patient)
return render(
request, 'patient_records/patient-problem-tum.html',
context={'prob': prob, 'vital': vital, 'social': social, 'patient': patient })
{% for y in prob %}
{{y.problem}}
{% endfor %}
{% for x in vital %}
{{x.height}}
{% endfor %}
{% for item in social %}
{{item.tobacco_smoking_status}}
{% endfor %}
Some Friendly Suggestions
"id" is a reserved word / function - I suggest changing id to maybe pid in your code.
Return an error to your view - You don't necessarily have to make this change, but I think its a good idea, and can even help with troubleshooting. I mean you should probably be returning an error or something to this chart if you can't find these objects with those ids in your database.
"get()" throws a DoesNotExist error if the id isn't found - You should catch the error and return it to the console you are making or do something like that.
views.py
#login_required()
def patienttumbilgiListView(request, pid):
context = {}
try:
patient = Patient.objects.get(aadhaarId = pid)
except DoesNotExist:
context['error'] = f"Could not find patient with id '{pid}'."
else:
context['prob'] = ProblemList.objects.filter(patient=patient)
context['vital'] = VitalSign.objects.filter(patient=patient)
context['social'] = SocialHistory.objects.filter(patient=patient)
context['patient'] = patient
return render(request, 'patient_records/patient-problem-tum.html', context=context)
template.html
{% if error %}
{{error}}
{% endif %}
{% for y in prob %}
{{y.problem}}
{% empty %}
Could not find problems.
{% endfor %}
{% for x in vital %}
{{x.height}}
{% empty %}
Could not find vitals.
{% endfor %}
{% for item in social %}
{{item.tobacco_smoking_status}}
{% empty %}
Could not find socials.
{% endfor %}
What Your Problem Is And How To Solve It
I am making django practising. I found a repo and edited to myself. When i came to the get data from models with foreignkey, i get query instead of data.
Based on this quote, I am assuming you want to know why the data is being returned as a queryset instead of as a singular result. From the docs:
filter() will always give you a QuerySet, even if only a single object matches the query - in this case, it will be a QuerySet containing a single element. If you know there is only one object that matches your query, you can use the get() method on a Manager which returns the object directly: one_entry = Entry.objects.get(pk=1).
Which is why you should use the for loop in your template.html. If you don't want to use that, then you should preprocess this data either by using get() instead of filter() or simply, in the context, send the [0] element to the template from your view.
So, to clarify, if you want to use {{prob.problem}} in your template, you need to change your view to either do prob = ProblemList.objects.filter(patient = patient)[0] or prob = ProblemList.objects.get(patient = patient). If you choose the first, you should check the length (prob = prob[0] if len(prob) == 1 else None), otherwise, if you choose the latter, you should wrap it with a try, except, else clause like this:
try:
prob = ProblemList.objects.get(patient=patient)
except DoesNotExist:
context['error'] = "Could not find ProblemList."
print("Does Not Exist")
else:
context['prob'] = prob
or you could just use the for loop that you have in place, I don't know how many entries you are expecting the query set to have per patient.
If I need to further clarify anything, please let me know.

Check whether value in dict with for loop in Django's template

I have the following data in my views.
months = [1,2,3,4,5,6,7,8,9,10,11,12]
mydict = {3:'a',4:'b'}
The key means month,if this month exists value,then render the value,else leave blank.
Here's my template.
{% for j in months %}
{% if mydict.j %}
<th class="align-middle">{{ mydict.j }}</th>
{% else %}
<th class="align-middle"></th>
{% endif %}
{% endfor %}
But the result always is blank.
I can access the value by mydict.3,but i can't get the value by mydict.j with a forloop.
If you write {{ mydict.j }}, then Django aims to lookup the value mydict['j'], not mydict[j].
Dictionary lookups and function calls (with arguments) are deliberately not allowed in a template, such that developers are encouraged to write business logic in the view not in the template. You can write a custom template filter, or make use of the jinja template renderer to allow this.
But it might be more sensical to do the mapping in the view:
def some_view(request):
mydict = {3:'a',4:'b'}
monthsanddict = [(x, mydict.get(x)) for x in range(1, 13)]
return render(request, 'some_template.html', {'monthsanddict': monthsanddict})
and in the template, you can then render this with:
{% for j, mydictj in monthsanddict %}
{% if mydictj %}
<th class="align-middle">{{ mydictj }}</th>
{% else %}
<th class="align-middle"></th>
{% endif %}
{% endfor %}

How to break "for loop" in Django template

I have this code
{% for account in object_list %}
<tr>
{% for field, value in book.get_fields %}
<th>{{ field.verbose_name }}</th>
{% endfor %}
</tr>
{{ break }}
{% endfor %}
I want to break the for loop after first iteration. break is not working
I think you should use slice to achieve your goal
{% for account in object_list|slice:":1" %}
There is no break in Django template system. Django template system is not programmed with python but with its own language.
Depending on what you need to do, you might find this question useful. Otherwise, just put the one and only account you are trying to print on HTML on a special field on your RequestContext.
You can't use break statement but you can choose not to print them on html. It's not a best solution but you can use it. I use the following one;
{%for tumbnail in image %}
{%if tumbnail.object_id == element.id %}
<img src="/media/{{ tumbnail.image }}" class="tr_all_hover"alt="">
{{ "<!--" }}
{%endif%}
{%endfor%}
{{ "-->" }}
Its basicly seem like this on browser.
http://i.stack.imgur.com/MPbR3.jpg
{% for i in list %}
{% if forloop.counter < 11 %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ i.product__name }}</td>
<td>{{ i.brand__name }}</td>
<td>{{ i.country__name}}</td>
<td>{{ i.city__name}}</td>
</tr>
{% endif %}
{% endfor %}
You can use your Django template system for loop in javascript for loop as inner loop and can use break as follows :-
for(var i=0;i<1;i++){
{% for owner in Owner %}
id = "{{owner.id}}";
if(id == pk1){
f="{{owner.flat}}";
break;
}
{% endfor %}
}
I found a way to do this with a condition. It's ugly and hacky, but it works (for me). first is what the OP wanted, but this answers the actual question more closely.
Given this:
obj = {
'children': [
{ 'possessions' : { 'toys': [] } },
{ 'possessions' : { 'toys': ['train'] } }
{ 'possessions' : { 'toys': ['train', 'ball'] } }
]
}
I wanted to know if my obj has any children with possessions that are toys.
Here's what I did:
Python Equivalent:
if ([child for child in obj.children if child.possessions.toys]):
# Whatever
Django Template:
My approach was to use regroup to build sets of candidates which did or didn't match the criteria:
{% regroup obj.children by possessions.toys|length_is:"0" as by_toys %}
{% for check in by_toys %}{% if check.grouper == False %}
Whatever
{% endif %}{% endfor %}
regroup builds a new object that is essentially:
[
{ 'grouper': '', 'list': [/*...*/] },
{ 'grouper': True, 'list': [/*...*/] },
{ 'grouper': False, 'list': [/*...*/] }
]
The length_is:"0" makes sure that we have at most three elements in that list and the grouper is either True or False or ''. Then we iterate over the list and check for a False value.
If there are no children it'd be an empty list and the if would never be hit.
If no children have toys, it'd be a list without a False grouper.
If all children have toys, it'd be a list with a False grouper.
If some children have toys, it'd be a list with False and True groupers.
In this case you can check if forloop.counter == 1 or if forloop.first and simply print that first item.
{% for account in object_list %}
{% if forloop.first %}
<tr>
{% for field, value in book.get_fields %}
<th>{{ field.verbose_name }}</th>
{% endfor %}
</tr>
{% endif %}
{% endfor %}
There is no break in Django template system but you can achieve an statement like break with bellow architecture. (Loop will go iteration but u don't do anything.)
1- Use with to define a variable to determine current status,
2- Use a template custom tag to change statement to negate current status.
in template use like this:
{% with statement=1 %}
{% for obj in listObject %}
{% if ifStatement and statement %}
{% changeStatement statement as statement %} // when u don't want to enter in if again.
Do your job here!!
{% endif %}
{% endfor %}
{% endwith %}
In template custom tags :
#register.simple_tag
def changeStatement(status):
return not status
Slicing is the best as mentioned on top!
Alternatively, you can use a template variable for more complex continue/breaks:
How can I use break and continue in Django templates?

Django only shows 15 objects...?

I have a very simple little Django 1.2 site, used to keep track of WEP keys cracked by students as a part of a lab, but I have run into a problem I can not figure out where it is: I have a template that lists solutions from the database, but it only lists 15 objects, even when there are many more (over 60) in the database table.
The view:
def index(request, message=None):
cracks_list = Crack.objects.all().order_by('-time')
return render_to_response('wifi/templates/index.html', {'cracks_list': cracks_list}, context_instance=RequestContext(request))
And the associated template:
{% if message %}<p><strong>{{ message }}</strong></p>{% endif %}
{% if cracks_list %}
<ul>
<table border="1">
<tr>
<td>Time</td>
<td>Student</td>
<td>Key</td>
</tr>
{% for crack in cracks_list %}
<tr>
<td>{{crack.time}}</td>
<td>{{crack.name}}</td>
<td>{{crack.key}}</td>
</tr>
{% endfor %}
</table>
</ul>
{% else %}
<p>No solution posted yet.</p>
{% endif %}
It seems very strange to me if I can not pass more than 15 objects to the template. And as far as I can tell there is nothing strange in the database. Any ideas? I assume it is something small and silly...
Check your template input before !
If this is cracks_list print it. It will help debug !
def index(request, message=None):
cracks_list = Crack.objects.all().order_by('-time')
for i in cracks_list:
print i
return render_to_response('wifi/templates/index.html', {'cracks_list': cracks_list}, context_instance=RequestContext(request))

Django: CheckboxSelectMultiple

Is it possible to render each checkbox individually, instead of it having to clump all the checkboxes together in a list, as it does by default? Something like
{{ myform.cbmultiple.0 }}
To render just the first checkbox? Actually the 0 would have to be a variable so I can loop...
The reason I'm asking is because I want to display these checkboxes in a rather complicated way, so the default widget doesn't work for me. I also don't really want to override the widget because it's much easier to render it using the template syntax than in python code, plus, that's a lot of work for a one-off.
No you can't do that because the whole HTML is generated by the widget's render method at once. You could only create your own widget class and override the render method so that it produces the HTML in a fashion that suits your purpose!
There is a way to render the CheckboxSelectMultiple() manually in the template so you can do what you want with it.
Take a look at this post for details.
The solution could be something like this:
<table>
<thead>
<tr>
<td> </td>
<td>V</td>
<td>S</td>
</tr>
</thead>
{% for pk, choice in form.options.field.widget.choices %}
<tr>
<td>{{ choice }}</td>
<td><label for="id_options_{{ forloop.counter0 }}"><input {% for option in app.options.all %}{% if option.pk == pk %}checked="checked"{% endif %}{% endfor %} type="checkbox" id="id_options_{{ forloop.counter0 }}" value="{{ pk }}" name="options" /></label></td>
</tr>
{% endfor %}
</table>