I want to generate a page using templates and content blocks. The homepage generates a bunch of checkboxes to generate a searchquery for some specific values.
<div id="searchbar">
{% for foo in bar %}
<input type="checkbox" name="foovar" value={{foo.name}}{%if foo.name in p %}checked=checked{%endif%}>{{foo.name}}<br>
{%endfor%}
<input type="submit" value="Submit">
</div>
<div id="searchresult">
{% block content %}
{% endblock %}
The value 'bar' is the parameter passed to the template containing all specific values:
return render_to_response('testlink/foobar.html',{'bar':strings_from_database})
Now, upon submitting the values, they are passed to my view, some magic happens, and the result is passed via
return render(request,'extend/extend.html',{'result':result,'p':queried_values})
result is the result, p contains the queried values (to keep the checkboxes checked after submitting).
{% extends "testlink/foobar.html" %}
{% block content %}
<b>results:</b> <br>
{% for result in result %}
{{result.someattribute}}<br>
{% endfor %}
{% endblock %}
Now, my problem: The checkboxes disappear, probably as the 'for foo in bar' loop is executed again. Is there a way to prevent that from happening, without to hardcode the checkboxes into my template? This would work (i did it with a few checkboxes, but doing this with too many searchvalues is no fun. Also i would like to avoid additional database hits and passing the parameters again.
I agree with the comments above, using forms is almost always a better idea. But in response to your problem, if you are not passing the bar variable to the template, the loop that parses the checkboxes will not be executed. You would need to add bar to the context for extend.html:
return render(request,'extend/extend.html',
{'result':result,'p':queried_values, 'bar':strings_from_database})
Are you not doing this just to prevent hitting the DB twice? Has it proven a very expensive query to run?
Apart from setting up caching, you can always pass ALL the checkboxes "names" along with the form. You can add hidden inputs, like so:
{% for foo in bar %}
<input type="checkbox" name="foovar" value="{{foo.name}}" {%if foo.name in p %}checked="checked"{%endif%}>{{foo.name}}<br>
<input type="hidden" name="foovar_all" value="{{foo.name}}" />
{%endfor%}
Then you need to collect the values with something like:
bar = request.POST.getlist('foovar_all')
But you would need to rethink your code so the bar variables hold just the names of those objects in both views, it looks like it is a list of objects currently. Again, is it really necessary to avoid that query?
Related
So I'm using Django and trying to dynamically add a users gists to the page using githubs embedded gists.
this is the loop
{% for i in snippets %}
<div class="tile is-4">
<div style="height:25vh;"><script src="https://gist.github.com/{{i.owner.login}}/{{i.id}}.js"/></div>
</div>
{% endfor %}
the list im looping through contains two items, however only the first is added.
if I do something along these lines however it correctly displays the two different id's
{% for i in snippets %}
{{i.id}}
{% endfor %}
I read that the github script calls document.write(), I have a gut feeling this is where my issue lies.
Would document.write() break my loop?
I have spent some time on this but cannot figure out the exact cause of the following behaviour.
I have a Django form and in the template I am trying to see if an integer is present in a list and then doing something with it.
{% if pk in form.area.value %} {# form.area.value is a list like [7,21] #}
do something
{% endif%}
Everything works fine except in cases where the form is reloaded after a validation error. In such cases, the list that I am comparing with, gets converted to list of strings (from a list of ints) on its own and the if test fails. So [7,21] above becomes ['7','21']
In case it helps, this is how the form is being rendered in the view:
On the GET request (where the if condition works fine):
form = SchoolForm(instance = school)
return render(request, 'edit-school.html', {'form': form, 'school_id': school_id})
After the POST request (where the if condition fails in the template):
form = SchoolForm(request.POST or None, instance=school, request=request)
return render(request, 'edit-school.html', {'form': form, 'school_id': school_id})
Update: Got it to work by converting string values after the POST request in the form back to int by declaring another method in the form (as suggested by #bruno in the answer below) and using it in the template. Here's the code snippet (of how its being used in the template):
<div class="checkbox">
{% for pk, choice in form.area.field.widget.choices %}
<label for="id_{{sub_type}}_{{form.area.name}}_{{ forloop.counter0 }}">
<input class="form-control" id="id_{{sub_type}}_{{form.area.name}}_{{ forloop.counter0 }}" name="{{form.area.name}}" type="checkbox" value="{{ pk }}" {% if pk in form.area_values %} checked="checked" {% endif %}/>
<span class="badge">{{ choice }}</span>
</label>
{% endfor %}
</div>
After the user submitted the form, {{ form.area.value }} (which in Python resolves to form["area"].value) is populated with the raw data from request.POST, which are indeed strings.
You didn't clearly explain what kind of "fancy thing" you're trying to do in the template so it's hard to come with a "best" solution for your use case, but as a general rule, templates are not the place for anything fancy - that's what Python is for (either in your view, in your form, in a custom templatetag or filter etc).
A very quick and simple solution would be to add a method to your form that returns the area boundfield values as ints:
class SchoolForm(forms.ModelForm):
# your code here
def area_values(self):
# XXX this might require some conditionals or
# error handling to be failsafe
# works with both python 2.x and 3.x
return [int(v) for v in self["area"].value()]
then in your template, replace {% if pk in form.area.value %} with {% if pk in form.area_values %}
I have managed to create the forms I need using modelformset_factory.
avaluos = Avaluo.objects.filter(Estatus__contains='CONCLUIDO',Factura__isnull=True)
FacturaFormset = modelformset_factory(Avaluo,form=FacturaForm,extra=0)
Currently this is generating the following HTML for each of the rows found:
<form id="id-FacturaForm" class="blueForms" method="post">[..]</form>
<form id="id-FacturaForm" class="blueForms" method="post">[..]</form>
<form id="id-FacturaForm" class="blueForms" method="post">[..]</form>
I want to submit all the forms using a single submit button.
Any ideas?
UPDATE
I ended up using django-crispy-forms which allowed me to gerate inputs for each row, and then I just manually added the form and submit.
self.helper.form_tag = False
{{example_formset.management_form }}
{% for a,b in olist %}
{{ b.id }}
<tr>
<td style="width:10px;"> {% crispy b %} </td>
<td> {{a.id}} </td>
</tr>
{% endfor %}
Read more into model formsets. You don't need to have separate form tags, it's the whole point of using a formset.
<form method="post" action="">
{{ factura_formset.management_form }}
<table>
{% for form in factura_formset %}
{{ form }}
{% endfor %}
</table>
</form>
Also, every time you use the id attribute more than once on a pageā¦ a developer cries themselves to sleep somewhere in the world.
I suspect you will need to do it using Ajax - otherwise as soon as one form is submitted you will not be able to go the other way.
There are a few jQuery form libraries that should make it relatively straightforward. For example, http://malsup.com/jquery/form/.
It would look something like:
$('#button-id').click(function() {
$('.blueForms').ajaxSubmit();
});
Of course, you'll then need to deal with error handling and waiting for all the forms to have submitted.
If you're trying to create many instances of the "same" form (this is, they all look equal), as if it were one of many childs belonging to a single, master element, you don't actually need to create a form tag for each of the formsets.
If I'm not mistaken, you're trying to edit many facturas for a single avaluo object. Am I right? The representation would be a single "avaluo" form with many inline formsets, one for each "factura".
Check out the inline formsets factory instead of the modelformset factory.
When using Django templates, should I have some templates that act like "subroutines", so to speak, or should I generate HTML from within my code in these cases?
For example, I have a template with several lists of names, each of which I want to turn into a select. Should I have a template that renders the name_list variable into a select, and do something like this:
#in the view:
return {'name_list_1': name_list_1,
'name_list_2': name_list_2,
'name_list_3': name_list_3}
#in the template:
{% with name_list_1 as name_list %}
{% include "sub_name_list_select.html" %}
{% endwith %}
{% with name_list_2 as name_list %}
{% include "sub_name_list_select.html" %}
{% endwith %}
{% with name_list_3 as name_list %}
{% include "sub_name_list_select.html" %}
{% endwith %}
Or should I have a function in my code, name_list_to_select_html, which does the same job, and do this:
return {'name_list_1_html': name_list_to_select_html(name_list_1),
'name_list_2_html': name_list_to_select_html(name_list_2),
'name_list_3_html': name_list_to_select_html(name_list_3)}
#in the template:
{{ name_list_1_html|safe }}
{{ name_list_2_html|safe }}
{{ name_list_3_html|safe }}
Or are both of these wrong and I am getting the philosophy totally wrong?
Additional question: in terms of speed, is it slow to constantly include templates? Is that a bonus point for the in-code html generation?
Generally, HTML should only be generated in the templating system or directly related code. That keeps the view of the data completely separate from the business and functional logic. I feel that's a proper separation of concerns. Go with your first solution.
As for performance, Django should probably take around the same amount of time running either code. But it has built-in view and template fragment caching if you know those segments of code don't need to be regenerated on every request.
I am using Google App engine, in the html file I want to show different screens to different users, ie,
they are not logged in the show them a log in screen
They are logged in and this is there first time to use the system
They are a returning user
So far the loops in my code is as follows
{% ifequal access_token None %}
<!-- Log in user-->
{% else %}
{% ifequal user_set None %}
<!-- First ever user in DB -->
{% else%}
{% for user in user_set %}
{% ifequal user.session_ID access_token %}
Logout {{user.user_name}}
{% else %}
<!-- add in counter? -->
{%endifequal%}
{% endfor %}
{% endifequal%}
{% endifequal %}
Is there anyway to increment a counter in the for loop as shown in the comments which could then be checked and if 0 then the user is not in the db already?
Firstly, it's not the greatest idea to loop through all your users in your template. It would be better to use a database filter query in your view to find the user, and set an appropriate variable to determine the action in your template. That being said, it is possible to get a forloop counter. Inside the forloop, it's given by forloop.counter (counts from 1) or forloop.counter0 (counts from 0). You can read more about it in the Django docs.
{% for user in user_set %}
{% ifequal user.session_ID access_token %}
Logout {{user.user_name}}
{% else %}
<!-- add in counter? -->
{{forloop.counter}} <!-- current count -->
{%endifequal%}
{% endfor %}
You should consider changing your way of redirection . It's not a good idea to iterate through all users in the db in the templates, Rather you should write a filter or move the logic to the controllers files. A decorator will come in handy for you. Coming to your question, You cannot set a counter inside template. If you want you can use the default
for loop variables. I don't think it will be of any use to you.
forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
forloop.revcounter The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
forloop.first True if this is the first time through the loop
forloop.last True if this is the last time through the loop
forloop.parentloop For nested loops, this is the loop "above" the current one
You should use decorators on views for users that are not authenticated. try the #login_required decorator.
For login counts, it better to create a database integerfield for your profile model, say login_counts. You then increase this anytime the user logs in. Getting the right login signal can be a bit tricky as there can be redirects and failed logins and other stuff. See this post for more details