How to set a variable value in a Flask HTML template - flask

I am trying to a assign a value to a WTForm field within the HTML template. I need to do it this way as the value assigned will depend on what iteration of the for loop it is in. Any other way of passing a value back to the python script will work as well.
I am currently getting an error. I am trying to assign the record field of the form equal to the id of the record it is currently viewing.
Below is the code:
<div class="modal-body">
<p>Name of Training: {{ record.training_name }}</p>
<p>Name of Provider: {{ record.training_provider }}</p>
<p>Date of Training: {{ record.date_submitted.strftime('%d/%m/%Y') }}</p>
<p>CPD Hours: {{ record.cpd }}</p>
<p>Certificate: View</p>
<form action="" method="post">
{{ form.hidden_tag() }}
<fieldset>
<div class="form-group">
{{ form.reason(class="form-control", placeholder="Reason for Denial (if applicable)") }}
{% set form.record.data=record.id %}
</div>
</fieldset>
When attempting to use the solution above I am getting the following error: jinja2.exceptions.TemplateSyntaxError: expected token 'end of statement block', got '.'

If I'm understanding you correctly:
{{ form.record(value=record.id, class="d-none") }}
instead of
{% set form.record.data=record.id %}

Related

Django ListView works but DetailView not displaying Model Data

I am helping my daughter with her computing Project for school. It is a simple generic forum type application.
She has a ListView for a model which works fine:
{% extends 'users/main.html' %}
<!-- Here is where our content will begin -->
{% block content %}
<h1>This is posts.html!</h1>
<br/>
{% for obj in object_list %}
<h2>{{ obj.topic }}</h2>
{{ obj.date_posted }}
<br/>
{{ obj.content }}
<br/>
Author: {{ obj.author }}
<br/><br/>
{% endfor %}
{% endblock %}
She then added a DetailView which is simply the same code with the loop removed:
{% extends 'users/main.html' %}
<!-- Here is where our content will begin -->
{% block content %}
<h1>This is posts.html!</h1>
<br/>
{{ obj.id }}
<h2>{{ obj.topic }}</h2>
{{ obj.date_posted }}
<br/>
{{ obj.content }}
<br/>
Author: {{ obj.author }}
<br/><br/>
{% endblock %}
This is then called with a '....post/1/' (post id = 1 does exist (checked via DB Browser and in the ListView) and the path and naming of the template is correct.
Frustratingly, this displays the page but not the details inside the django temp language brackets (object.topic etc)!
When I look at the page source for the section dealing with the detail, I get:
screenshot of page
and the source code looks like so:
<h1>This is posts.html!</h1>
<br/>
<h2></h2>
<br/>
<br/>
Author:
<br/><br/
It is simply ignoring the bracketed templating code - any ideas?
Django DetailView returns 'object' inside context by default.
If you did not change 'context_object_name' variable, then use {{object}} instead of {{obj}}
<h1>This is posts.html!</h1>
<br/>
{{ object.id }}
<h2>{{ object.topic }}</h2>
{{ object.date_posted }}
<br/>
{{ object.content }}
<br/>
Author: {{ object.author }}
<br/><br/>
Really thanks a lot for all of this.
I corrected my template to include 'object' and made it march all conventions to avoid having to send in context information.
It still wouldn't work.
I rebooted localhost repeatedly because it all made no sense.
Finally, I rebooted my daughters PC and immediately, everything worked.
A lesson learned and as a dad helping a 17 year old daughter who did his Computer Science degree 40(!) years ago, another lesson in how complicated and challenging understanding a framework can be.
I must say - it has been fun.
Thanks again,
Howard.

WTForm validator not giving feedback on non-numeric values

I have a wtform and want to give feedback to users if they enter a non numeric value. I am using
availablequantity = IntegerField('Available quantity',
validators=[ NumberRange(min=1, max=100), DataRequired()])
and on html side I have,
<div class="form-group">
{% if form.availablequantity.errors %}
{{ form.availablequantity(class="form-control is-invalid") }}
<div class="invalid-feedback">
{% for error in form.availablequantity.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.availablequantity(class="form-control", placeholder="Available quantity") }}
{% endif %}
</div>
now if user enters a numeric value things are fine but if they enter non-numeric values, I don't get any useful feedback (I was expecting something like, "you must enter a numeric value between 1 and 100")
Add the following in your request (not in the form class:
form.availablequantity.errors.append("Enter num between 1 and 100")
or add message argument
NumberRange(min=1, max=100, message='Num must be between 1 and 100')

Django: Accessing queryset in ModelMultipleChoiceField from template

I'm creating a panel where a user can assign an assignment to other users. I'm attempting to build this with the ModelMultipleChoiceField and a form called AssignedUsersForm
forms.py
class AssignedUsersForm(ModelForm):
class Meta:
model = Assignment
fields = ['users']
custom_users = CustomUser.objects.all()
users = forms.ModelMultipleChoiceField(queryset=custom_users, widget=forms.CheckboxSelectMultiple())
template
<form method="post" id="assigned_users_form">
{% csrf_token %}
{{ assigned_users_form.errors }}
{{ assigned_users_form.non_field_errors }}
<div class="fieldWrapper">
{{ assigned_users_form.content.errors }}
{% for user in assigned_users_form.users %}
<div class="myradio">
{{ user }}
</div>
{% endfor %}
<br>
<div style="text-align:center;">
<input class="input-btn" type="submit" value="Save" name='submit_assigned_users_form'>
</div>
</form>
I've successfully rendered each of the options for CheckboxSelectMultiple individually in my HTML.
Unfortunately, each iteration of 'user' renders CustomUser object (#) - the default name for the object.
From what I understand, the Checkbox widget does not pass the original queryset to the template. Thus, I'm unable to access the model attributes of each user and render information such as name, profile picture, etc.
Is there a method of accessing the actual object that's represented in the checklist, instead of the _ str _ value?
I've considered running a parallel iteration of queryset in the template, but I'm not sure if that's possible in Django.
I've also considered creating custom template tags to access each object based on the id in str, but that seems like overkill?
Is there a more intuitive method that I'm missing here?
I found a work around by creating a template_filter that takes the checkbox value and returns the corresponding object to the template.
template_tags.py
#register.filter(name='get_user')
def get_user(user_id):
user = CustomUser.objects.get(pk=user_id.value)
return user
template
<form method="post" id="assigned_users_form">
{% csrf_token %}
{{ assigned_users_form.errors }}
{{ assigned_users_form.non_field_errors }}
<div class="fieldWrapper">
{{ assigned_users_form.content.errors }}
{% for user in assigned_users_form.users %}
<div class="myradio">
{% with customuser=user.data.value|get_user %}
{{user.tag}} {{customuser.first_name }}
{% endwith %}
</div>
{% endfor %}
<br>
<div style="text-align:center;">
<input class="input-btn" type="submit" value="Save" name='submit_assigned_users_form'>
</div>
</form>
Essentially, this code looks at the checkbox widget iteration (user) and gets the value, passes that value to the template tag and then returns the associated object back to the page.
Not the best solution given that you're repeating the query search for each object, rather than gathering them all in one go. But this is the best I could come up with.

Django: How to output error_message in paragraph <p> instead of list <li> format

I have a simple form which uses a SessionWizardView to spread it over a number of pages. Below is an example of one of the questions.
first_name = forms.CharField(max_length=100, label='What is your first name?', error_messages={'required': 'Please enter your first name'})
Which renders out as
<label for="id_0-first_name">What is your first Name?</label>
<ul class="errorlist">
<li>Please enter your first name</li>
</ul>
<input id="id_0-first_name" maxlength="100" name="0-first_name" type="text" />
Can anyone tell me hwo to change the error output so that it is in <p> Paragraph </p> format rather than <li> List item </li> format?
I am using Django 1.6.2
You'll have to create a class that does renders the HTML as you would want it. See the docs here.
The example from the docs:
from django.forms.util import ErrorList
class DivErrorList(ErrorList):
def __unicode__(self):
return self.as_divs()
def as_divs(self):
if not self: return u''
return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
f = ContactForm(data, auto_id=False, error_class=DivErrorList)
f.as_p()
You can do as #schillingt suggested and create your own error list class.
Or, if you want to handle this in your template, you can use something like:
<form method="post" action="/some-view/">
... other fields, etc. omitted ...
<!-- The label and form field -->
{{ form.first_name.label_tag }}
{{ form.first_name }}
<!-- Output any errors -->
{% for error in form.first_name.errors %}
<p>{{ error }}</p>
{% endfor %}
... other fields, etc. omitted ...
<button type="submit">Submit</button>
</form>
Update
In order to do this in a cleanly repeatable way, make a template named form-field.html:
{{ field.label_tag }}
{{ field }}
<!-- Output any errors -->
{% for error in field.errors %}
<p>{{ error }}</p>
{% endfor %}
Then, update your main template:
<form method="post" action="/some-view/">
... other fields, etc. omitted ...
{% with field=form.first_name %}
{% include "form-field.html" %}
{% endwith %}
... other fields, etc. omitted ...
<button type="submit">Submit</button>
</form>
You can then make updates to the single form-field.html template and update all of your forms, and it makes your main template a bit simpler

fetch variables in django templates

I am new to django .
I am facing a small problem but unable to solve it.
In my template when I try to access any variable using {{ }} but it returns blank while displaying something as detailview.whereas it works fine in listview.
CODE:urls.py
urlpatterns = patterns('',
url(r'^$', ListView.as_view(
queryset=Profile.objects.all().order_by("First_Name"),
template_name="STUDENT_REGISTRATION.html")),
url(r'^(?P<pk>\d+)/$',DetailView.as_view(
model=Profile,
template_name="Profile.html")),
TEMPLATE:
{%extends "base.html" %}
{% block content %}
<h2>Registration No. :- {{ Profile.Registration_No }} <br>
Full Name : {{ Profile.First_Name }} {{ Profile.Last_Name }} </h2>
<div class="Profile_meta">
{{ Profile.Date_of_Birth}}
</div>
<div class="Profile_body">
{{ Profile.Permanent_Address|safe|linebreaks }}
</div>
{%endblock%}
Plz help..
You should refer to your Profile instance as:
{{ object.First_Name }} {{ object.Last_Name }}
By the way, take a look at PEP8, try to keep CamelCaseNames for class names and underscores_names for instances. It will make your code easier to read.