Django Template Won't Display List - django

I've had a look at previous questions, and I'm unable to find an answer to my issue.
I'm trying to display a 2D list, which I have done earlier in the HTML with a different list.
I've used a similar method for the other list but it wont display, I'm just getting the headers.
HTML:
<table class="listtable" >
<thead>
<tr>
<th>No</th>
<th>Account No</th>
<th>Time</th>
<th>Message</th>
</tr>
</thead>
{% for person in user %}
<tr>
{% for message in person %}
<td>{% autoescape off %}{{ message }}{% endautoescape %}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
I've printed the list in the view, so I know that within the view it is correct. I am 100% sure that I've used the correct variables as well.
The code in the view is similar to:
user = get_data_from_other_source()
for item in user:
print(item)
The print displays exactly what it should.
The list is along the lines off:
[4, '<account number>', '<time>', 'somestring']
[3, '<account number>', '<time>', 'somestring']
The page source says:
<table class="listtable" >
<thead>
<tr>
<th>No</th>
<th>Account No</th>
<th>Time</th>
<th>Messages</th>
</tr>
</thead>
</table>
EDIT: Moderated view code..
#login_required(login_url='/login')
def page_control(request):
acc_no = request.session['acc_no']
user = setup_page_control (acc_no)
for item in user:
print(item)
return render_to_response("<htmlfile>.html",
locals(),
context_instance=RequestContext(request))
def setup_user_control(acc_no):
messages = <outside magic>
user = reversed(messages)
return user
I have gutted a lot out of the code, and changed variable names etc..
I've only deleted stuff which I am 100% sure are not the problem

An explanation for the issue you found:
reversed() returns a reverse iterator. This is NOT the reversed list as you expect it to be:
>>> a = [1,2,3,4,5]
>>> print reversed(a)
<listreverseiterator object at 0x...>
As you can see, reversed(a) is not the list in reverse, but the actual iterator itself. In order to get the reversed list like you want you can use:
user = list(reversed(messages))
# or
user = messages[::-1]
(source: How can I reverse a list in python?)

I believe your response should be like this:
return render_to_response("<htmlfile>.html",
{'user':user},
context_instance=RequestContext(request))

I've found my issue, but I'm not sure why it happened.
When I removed:
user = reversed(messages)
The template was willing to output the list again. Awfully odd. If anyone knows why, it would be great for an explanation :)

Related

How to render an arbitrary set of key->value pairs from a JSONField in a Jinja2 template?

I'm trying to add debug information to a frontend; for reasons that don't need to be gone into at the moment I'm storing the pertinent information in a JSONField.
Storing and retrieving the information works correctly, but when I try to render it via J2 to the page it's supposed to be at I'm running into some issues.
Here's the segment in question:
{% for log in connection.debug_logs.all %}
<tr>
<td></td>
<td>{{ log.log_message }}</td>
<td>
{% for key in log.log_data %}
{{ key }}: {{ log.log_data.key }} <br/>
{% endfor %}
</td>
</tr>
{% endfor %}
What I'm hoping for is for that to produce a series of lines of key: value. What I'm getting instead is:
<td>Login requested by vmx1.internal (11.22.33.44)</td>
<td>
Framed-Route: <br/>
Service-Type: <br/>
Framed-IP-Address: <br/>
Framed-IPv6-Route: <br/>
control:Auth-Type: <br/>
Framed-IPv6-Prefix: <br/>
Delegated-IPv6-Prefix: <br/>
ERX-Egress-Policy-Name: <br/>
ERX-Ingress-Policy-Name: <br/>
ERX-Virtual-Router-Name: <br/>
control:Cleartext-Password: <br/>
</td>
Using {{ log.log_data | pprint }} does yield the keys and values, but renders them as a plaintext JSON string which gets flattened by the html renderer and isn't terribly useful for debugging purposes.
Trying 'log.log_data[key]' instead yields a 'Could not parse the remainder' error.
I've tried the suggestions in this question as well as these and a few others that came up during google searches, but none of them seem to address this issue -- all of them are either working with known keys, working with an actual dict instead of a JSONField, or sometimes both.
I'm probably missing something very simple and straightforward, but I've run out of ways to phrase my question in a search engine. Any tips?
EDIT No, it is not actually a dictionary. I've also tried the solutions in this answer and that leads back to the Could not parse the remainder error.
So the data I'm looking for is absolutely there, I'm just having issues trying to get it to render properly.
Third and final edit: The problem was apparently that Django templates are not quite Jinja2 templates, and rather than {% for key, value in log.log_data.items() %} I needed to use {% for key, value in log.log_data.items %}
Do the conversion from json inside your view to have a greater range of utilities than inside the jinja2 template world.
import json
DEBUG_LOGS_JSON = "[
{"log_data": {"Framed-Route": "route1", "Service-Type": "type1"}, "log_message": "my"},
{"log_data": {"Framed-Route": "route2", "Service-Type": "type2"}, "log_message": "name"},
{"log_data": {"Framed-Route": "route3", "Service-Type": "type3"}, "log_message": "Tarquinius"},
]"
def my_view(request):
my_dict = json.loads(DEBUG_LOGS_JSON) # instead you could also restructure the data passed to the template here.
return render("my_template.html", context=my_dict)
{% for dictionary in my_dict %}
<tr>
<td>{{ dictionary.log_message }}</td>
<td>
{% for key, value in dictionary.log_data.items() %}
{{ key }}: {{ value }} <br/>
{% endfor %}
</td>
</tr>
{% endfor %}
If this does not represent the structure of your json, then please provide an example. Let me know how it goes.

#DJANGO - I need to display two (or more) rows of a table in my view, currently I can only display one of the rows

Hello people I am working with ticket creation and there is a 1-N relationship, (a ticket can have multiple messages)
I have a view that creates a ticket, in the creation process a message is added - All right here
I have a view that adds a new message to the ticket(s), thus 'activating' the 1-N - All right here
I have a ticket detail view view (code below) - Here starts my difficulty
def ticket_by_id(request, ticket_id, message_id):
mesTicket = MessageTicket.objects.get(pk=message_id)
ticket = Ticket.objects.get(pk=ticket_id)
return render(request, 'support/ticket_by_id.html', {'ticket': ticket, 'messageticket': mesTicket})
the code view above works when the ticket has only one message, but how can I display the multiple messages in this view?
For example in the image below there is my database, highlighting two lines that are linked to ticket 9
database, highlighted in ticket messages 9
Below is an image of my ticket detail view
my detail view of the ticket
How should I display in the view the two messages (or 3, or 4, anyway... more than one) that are related to the ticket, as I would show in my view (image 2) lines 9 and 12 (currently it is only displaying the first registered line linked to the ticket, in this case line 9 of the table) of the my table which are the ones that make up the 1-N with the ticket 9 (image 1)
my html page:
{% extends 'web/base.html' %}
{% block title %} Ticket #{{ticket.id}} {% endblock %}
{% block content %}
<div class="ticket">
<table class="styled-table">
<h2> Ticket #{{ticket.id}}</h2>
<style>
td {
padding: 15px;
}
</style>
<br>
<tbody>
<tr>
<td>ID: </td>
<td>{{ticket.id}}</td>
</tr>
<tr>
<td>Author: </td>
<td>{{messageticket.author_id}}</td>
</tr>
<tr >
<td>Status: </td>
<td>{{ticket.status}}</td>
</tr>
<tr>
<td>Content: </td>
<td>{{messageticket.content}}</td>
</tr>
<tr>
<td>Created At: </td>
<td>{{ticket.created_at}}</td>
</tr>
</tbody>
</table>
</div>
{% endblock %}
First of all, why does your message is not fetch with the id of your ticket, this would ease your work
Second to print multiple "messageticket" you should use something like:
{% for t in messageticket %}
<tr>
<td>Content: </td>
<td>{{ t.content }}</td>
</tr>
{% endfor %}
A loop is needed. As i don't know how messageTicket is done i can't really help you.
But if messageticket have a foreign_key to Ticket then you should be able to to acces it through ticket with ticket.messageticket_set (messageticket_set can be modified if "related_name=" is used in your foreign_key field)
https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/
and there you'll have all your messageticket
Hope it help =)

FF92.0 on linux introduces caching issues with django 3.2 inline forms

I've noticed a strange behavior with FF 92.0 (Manjaro Linux, but likely all linux I guess) when using inline forms.
Setup:
Django inline forms
A way to add inlines ajax. I'm using the django forms empty_form
Some arbitray # of inline saved on the server for that object (for example, say 3)
Load the form, add say 2 inlines using javascript. TOTAL_FORMS now shows value=5
Do NOT submit the form, but F5 for a refresh instead
After reload, the inlines shown in the table will mirror that of the server
However the TOTAL_FORMS from the management_form will show value=5, instead of the 3 it should.
page.js:
function insert_inlinedets_form () {
let form_idx = $('#id_details-TOTAL_FORMS').val();
console.log("inserting new form " + form_idx);
let newrow = $('<tr></tr>').appendTo($('#details_form'));
newrow.append($('#empty_form_inlinedets').html().replace(/__prefix__/g, form_idx));
$('#id_details-TOTAL_FORMS').val(parseInt(form_idx)+1);
console.log("added row to inlinedets formset");
};
function remove_inlinedets_form () {
console.log("remove last form ");
let form_idx = $('#id_details-TOTAL_FORMS').val();
if (form_idx>0) {
$('#details_form > tr').last().remove();
$('#id_details-TOTAL_FORMS').val(parseInt(form_idx)-1);
console.log("removed row from inlinedets");
calc_grand_total(); // existing rows haven't changed but the total might
} else {
$('#id_details-TOTAL_FORMS').val(); // if no form left, this SHOULD be 0.
console.log("No more dets left - nothing done.");
}
};
html - empty form:
<div style="display:none">
<table>
<thead></thead>
<tbody>
<tr id="empty_form_inlinedets">
{% for field in formset.empty_form %}
{% if field.is_hidden %}
<td style="display:none;">{{field}}</td>
{% else %}
<td>{{field}}</td>
{% endif %}
{% endfor %}
</tr>
</tbody>
</table>
</div>
html - target table to append to:
<div class="table-responsive shadow encart">
{{ formset.management_form }}
{{ formset.non_form_errors }}
<table class="table table-bordered dbase-table" id="bottom_product_form" width="100%" cellspacing="0">
<caption style="caption-side:top">Products</caption>
<thead>
<tr>
<!-- th content -->
</tr>
</thead>
<tbody id="details_form">
{% for form in formset %}
<tr>
<!-- td content -->
</tr>
{% endfor %}
</tbody>
</table>
</div>
I have validated the following:
The response.rendered_content that the server returns does indeed show the correct TOTAL_FORMS number (3, in the above example)
This does NOT happen upon a hard refresh (ctrl shift r on FF). TOTAL_FORMS, under the same setup, shows the correct # of 3.
This does NOT happen on Google Chrome upon a normal refresh.
So.... any ideas on how I should approach this? What setting could be causing the issue? Please consider in any answer:
I won't have control of user behavior. So simply "not using soft refresh on FF" isn't valid.
I won't have control of user browser settings, so adjusting some settings wouldn't really work (although KNOWING which FF setting may cause the issue is still useful)

executing python script in django with arguments from the frontend

I want to manipulate the values associated with the entries of an external mongodb database using a django webapp.
I've created the app and I'm currently displaying all the entries and their associated value in a simple table.
My idea is simply to create a button, that calls a python script with an argument (the id of that entry) and then changes it from false to true. The problem is, this seems like rocket-science, I've been at this for days now and I just can't get it to work as I have little to no proficiency when it comes to Ajax or Jquery, and all relevant examples I can find don't simply seem to pertain very well to my situation despite how basic it would appear, nor fit with Django 2.0+.
I'm using Django 2.1.5
def change_value(idnumber):
db_value = get_db_status_value(idnumber)
if db_value is True:
change_db_entry_status(idnumber, False)
else:
change_db_entry_status(idnumber, True)
my_template.html
<table>
<thead>
<tr>
<th> Status </th>
<th> Button </th>
</tr>
</thead>
<tbody>
{ % for entry in entry_data % }
<tr>
<td> {{ entry.status }} </td>
<td> <button type="button">{{ entry.idnumber }}</button> </td>
</tr>
</tbody>
{% endfor %}
</table>
I simply can't figure out how I can get the change_value function in there that I can create a button for and include an argument ( entry.idnumber ). This seems incredibly difficult, which from what I understand is a design principle, but it seems a shame if I can't even accomplish something as basic as above.
I was hoping someone could explain how I'm actually supposed to go about this? So far, it seems I require AJAX or Jquery (unfortunately, I barely know the basics of this, and what usually trips me up is that the urls.py which exist in both project and application level seems to work a little different in django 2.0+ compared to older versions)
This isn't actually difficult. It's just that you're missing an understanding of the relationship between the client and the backend code.
Once the template is rendered, the user sees it as HTML in their browser. That's it as far as the backend (ie Django) is concerned. The only way to run any further code on the server is to send another request. A request involves the browser contacting the server, which requires a URL and a view in Django.
Now, one way to send that request is via Ajax, but for your purposes that isn't necessary; since you're just learning, it's easier if you make it a simple form. So, your template might look something like this:
{% for entry in entry_data % }
<tr>
<td> {{ entry.status }} </td>
<td><form action="{% url 'change_value' idnumber=entry.idnumber %}" method="POST"> {% csrf_token %} <button type="submit">{{ entry.idnumber }}</button> </form></td>
</tr>
{% endfor %}
</tbody>
Notice how every iteration of the for loop has a separate form, which posts to a specific URL including the ID number.
Next you need a URL:
path('change_value/<int:idnumber>/', views.change_value, name='change_value'),
and update your function to actually be a view, which needs to accept a request and return a response:
def change_value(request, idnumber):
if request.method != "POST":
return HttpResponseNotAllowed()
db_value = get_db_status_value(idnumber)
if db_value:
change_db_entry_status(idnumber, False)
else:
change_db_entry_status(idnumber, True)
return redirect('/')
You always need to redirect after a POST, but you could redirect back to the same URL that rendered my_template in the first place. (Also note I've put in a test to make sure the user is actually sending a POST; you don't want Google to crawl this URL and flip your values for you.)
And that's it, now you have a button that should toggle your value.
The answer from #Daniel is enough for you. But if you want to use ajax so that the page does not have to refresh to change the vaue, you may do something like:
In your template make changes as:
<table>
<thead>
<tr>
<th> Status </th>
<th> Button </th>
</tr>
</thead>
<tbody>
{ % for entry in entry_data % }
<tr>
<td id="status"> {{ entry.status }} </td>
<td> <button type="button" onclick="change_status(this)" id="{{ entry.idnumber }}">{{ entry.idnumber }}</button> </td>
</tr>
</tbody>
{% endfor %}
and a script as:
<script>
function change_status($this){
var request_data = $this.id;
console.log("data: " + request_data);
$.post({
url: "url that leads to your view",
data : { request_data: request_data},
success : function(json) {
document.getElementById('status').innerHTML = "" //insert the data returned from the function
}
})}
</script>

sending html to django template from view

I am new to django so I may be going about this the wrong way (pretty sure I am).
Trying to get a webpage to display data from a postgresql DB in a table showing a status for a list of servers.
This is part of the template
<div class"row"=""><div class="span3" style="background-color:lightyellow; margin-left:20px">
<table class="table table-bordered table-condensed">
<thead>
<tr>
<th>Server</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{{ res }}
</tbody>
</table>
</div></div>
In my view I have this,
message = []
for res in data:
message.append(" <tr>")
message.append(" <td>" + str(res).split("'")[1] + "</td>")
if str(res).split("'")[3] == 'No':
message.append(" <td><FONT COLOR=\"008200\">Available</FONT> </td>")
else:
message.append(" <td><FONT COLOR=\"FF0000\">Down</FONT> </td>")
message.append(" </tr>")
return render_to_response('health.html', {'res':message}, context_instance=RequestContext(request))
If I print that instead of doing the append I get the resulting HTML I would expect.
As it currently is, I don't get anything displayed on the webpage in that table.
I don't expect it to render the list necessarily, but would have thought something should have showed up in the table even if it was incorrect format.
Should this HTML processing be done in the template and not the view?
Yes, it is usually best to do all HTML processing in the template. This way you can separate your database access logic from your display logic and thereby reduce coupling. It also means you can easily re use template.
So you should use the view function to get the appropriate objects and pass them to the template as variables.
Still, you are sort of on the right track. In order for your {{res}} variable to display properly I think you will need to change the template to.
<tbody>
{% for message in res %}
{{ message }}
{% endfor %}
</tbody>
This should iterate over the elements in the res variable which you passed to the template.