WTForms how to use description paramter - flask

I have some simple boolean field and I want to add a short description.
I specified a description parameter but it seems like no effecr.
How it suppose to work at all?
from wtforms import BooleanField, Form
class AdminUsersForm(Form):
foo = BooleanField(label='foo', default=True, description='foo')
<form method="GET">
<div>
{{ form.foo.label }}
{{ form.foo(placeholder=checkbox.description)}}
# No description impact at all, even tooltip.
</div>
</form>
I found this answer but not sure that it's my case

You almost have it. Try changing your 'placeholder' to display the text that you have defined:
{{ form.foo(placeholder=form.foo.description)}}
You access this the same way as the form.label, simply by calling the parameter of the field of the form.

Related

Have url with pk or id to redirect to update page in Django error message

I've created an app, and on the CreateView page, the Submit button works fine to create a new S Reference. I also created an error message if the input value matches an existing Reference. I created button in the error message part and tried to link it to update the page to update these reference fields, like primary contact. I tried many options but have not got right code for the argument with pk or id to get individual record update page.
this is the url in error message.
I tried quite few pk, id options, none of them works.
'pk'=self.pk;
{'pk'=self.pk};
object.id
some code as below
models.py
class LNOrder(models.Model):
reference_number = models.CharField(max_length=15,blank=True, null=True, unique=True, error_messages={'unique':"This reference already exists."})
primary_contact = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
urls.py
urlpatterns = [
path('lfcnotifier', LNCreateView.as_view(), name='lnorder_create'),
path('lfcnotifier/<int:pk>', LNDetailView.as_view(), name='lnorder_detail'),
path('lfcnotifier/<int:pk>/update/', LNUpdateView.as_view(), name='lnorder_update'),
]
template
<div class="input-group mb-3">
<div class="input-group-prepend w-225px">
<label class="input-group-text w-100">S Reference</label>
</div>
<input name="reference_number" type="text" class="form-control" placeholder="Enter your S Reference"/>
<button class="btn btn-primary cardshadow " data-toggle="tooltip" title="Click to submit" style="width:200px;" type="submit">submit</button>
{%for field in form %}
{% for error in field.errors %}
{{ error }} Update Request
{% endfor %}
{% endfor %}
Views.py
class LNCreateView(SuccessMessageMixin,LoginRequiredMixin,CreateView):
model = LNOrder
template_name = 'lfcnotifier/lnorder_create.html'
form_class = LNOrderForm
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
I expect when users click on Update Request button, it'll open the update page to edit the individual reference.
but I got message "Could not parse the remainder: '=self.pk' from ''pk'=self.pk'".
I get slightly different messages when I try the above different options.
I would like to have the right code for the URL to update the page when the Update Request button is clicked.
Thanks,
Additional background, I only put some of template code here to save space. They are in form section. If I use the following code
Update Request
instead of
Update Request
it can open the full list page without issue. I can go to update page from full list page without issue. But I want to open update page from here directly other than have one more step.
This is all kinds of confused.
For a start, you can't use a string on the left-hand side of an expression, either in pure Python or in Django templates.
But secondly, you don't have anything called self there. What you do have would be passed from the view; however it's not clear from the code you have posted which actual view this is. It doesn't seem to be that CreateView, because you are linking to the update. But assuming it's actually the LNDetailView, and assuming that that actually is a DetailView, you have access to the current object in the template exactly as object.
So you would do:
{% url 'lnorder_update' pk=object.pk %}
However again, this makes no sense to actually do. You can't submit a form via an a. You need a <form> element with a button.

Wagtail not pulling through custom field panels

I'm overriding the wagtail AbstractFormField panel attribute in the following way:
...
before_input = RichTextField(verbose_name=_('before input'), blank=True)
after_input = RichTextField(verbose_name=_('after input'), blank=True)
panels = [
FieldPanel('label'),
FieldPanel('before_input'),
FieldPanel('after_input'),
FieldPanel('required'),
FieldPanel('field_type', classname="formbuilder-type"),
FieldPanel('choices', classname="formbuilder-choices"),
FieldPanel('default_value', classname="formbuilder-default"),
]
where the other panels are what comes out of the box.
This is working perfectly on the admin side and also saving as rich text into my database
I am pulling this through to my form in my template in the following way:
<form action="{% pageurl page %}" method="POST" class="lm-ls1" id="feedback-form">
{% csrf_token %}
{{ form.question1.help_text }} <!-- Simpler non interable way -->
{{ form.question1.before_input }}
<p>---------------</p>
{% for row in form.fields.values %}
{{row.choices}}
<p>---------------</p>
{{row.help_text}}
<p>---------------</p>
{{row.before_input}}
{% endfor %}
</form>
But I am only getting html output for the form panels excluding the before_input and after_input ones
I am getting through roughly the following:
Overall, how did you feel about the service you received today?
---------------
[('Very satisfied', 'Very satisfied'), ('Satisfied', 'Satisfied'),
('Neither satisfied nor dissatisfied', 'Neither satisfied nor dissatisfied'), ('Dissatisfied', 'Dissatisfied'), ('Very dissatisfied', 'Very dissatisfied')]
---------------
Overall, how did you feel about the service you received today?
---------------
---------------
How can I access the before_input field panel data stored in the _formfield wagtail table?
Bit late but hopefully this still helps you or someone else out there.
How Wagtail Forms Work
Wagtail forms provided to the view context for AbstractFormPage models is a fully instanced Django Form. This means that you will only ever find values in the form that can be given to a Django Form.
This includes fields, which are instances of Django's Fields (eg. CharField) and there is no simple way to add additional attributes to these fields.
You can see how the Form object is built in the Wagtail FormBuilder class definition.
1 - Make a Custom Template Tag
A somewhat simple way to get additional attributes on your FormField (Wagtail's FormField) is using a template tag.
Create a new file in in a folder templatetags in your app, and build a simple_tag that will take the form_page, the field (which will be a Django Field instance) and a string of the attribute name you want to get.
# myapp/templatetags/form_tags.py
from django import template
from django.utils.html import mark_safe
register = template.Library()
#register.simple_tag(name='form_field_attribute')
def form_field_attribute(form_page, field, attribute_name, default=None):
"""Return attribute on FormField where field matches 'field' provided."""
# field is a django Field instance
field_name = field.name
results = [
# if html is stored, need to use mark_safe - be careful though.
mark_safe(getattr(form_field, attribute_name, default))
# get_form_fields() is a built in function on AbstractFormPage
for form_field in form_page.get_form_fields()
# clean_name is property on AbstractFormField used for Django Field name
if form_field.clean_name == field_name]
if results:
return results[0]
return default
2 - Revise your form_page.html Template
In your template, cycle through your form (this is the Django Form instance) and use the template helper to get you the extra attributes you need. Example below, passing in page or self will work the same as they are both the instance of your FormPage.
<form action="{% pageurl page %}" method="POST" role="form">
{% csrf_token %}
{% for field in form %}
<div>{% form_field_attribute page field 'before_input' %}</div>
{{ field }}
<div>{% form_field_attribute page field 'after_input' %}</div>
{% endfor %}
<input type="submit">
</form>

dynamic form in Flask

in a movie rating app,I would like to generate a WTF form in flask with dynamic number of fields. i.e, if there are three movies, there will be three fields.
I thought about a few options, but none of them worked:
class RatingForm(Form):
rating = TextField("rating",[validators.Length(min=1, max=1)])
movie_order=TextField("movie",[validators.Length(min=1, max=1)])
submit = SubmitField("submit rating")
pass a parameter to the form object - I don't see how can I pass a parameter to this kind of class
make a loop inside the template, thus generate and return multiple forms, and choose the correct one. this also doesnt work, since the request.form is immutableDict, and I end up having multiple fields with the same key, which I cant access.
{% for movie in movies_to_rate %}
<p>
<form method="POST" enctype="multipart/form-data" action="/rate">
{{ movie}}
{{ forms[movie].rating}}
{{ forms[movie].submit }}
<input type="submit" value="Go">
</p> {% endfor %}
any ideas about what can I do?
I think you can generate a list of TextField's as a class member instead of using one field object. (Though it looks a bit weird, I assume your validators are what you meant.)
class RatingForm(Form):
def __init__(self, count):
self.ratings = [TextField("rating_" + str(i), [validators.Length(min=1, max=1)])
for i in range(count)]
...

Dynamic Forms (Formsets) in Flask / WTForms?

In Django you have a multiple form feature called Formsets, which you can use to create multiple forms into the same template. I am trying to achieve something similar in Flask / WTforms.
<form action="{{ url_for('request-accept') }}" method='post'>
<table>
<tbody>
{% for request in requests %}
<tr>
<td>
<div class="person-header">
<img src="{{request.profile_pic_url}}" class="img-circle profile-image"/>
<p class="person-header-text">{{request.fullname()}}</p>
</div>
</td>
<td>
<input type="checkbox" id="{{request.key.urlsafe()}}" name="checkbox{{loop.index}}">
</td>
</tr>
{% endfor %}
</tbody>
</table>
<input class='submit btn btn-primary' type=submit value="Connect">
</form>
The idea is having one form that wrapps all the checkboxes, which the user like to tick to become friends with. As it currently stands I am not really generating any form class in Flask, since I don't know how to make a dynamic FormSet, hence I create the form dynamically inside the html.
The caveat is though, I don't know how to retrieve the selected user id via the checkbox. (I have stored it in the id because I didn't know better)
But I can't access the id in request.values['checkbox1']. I can only see if its on or off.
Any suggestions how to solve this please?
The problem
Your problem is that id is not sent back to the server - only value is ... and since your checkboxes don't have a value attribute the default value is used, which happens to be on.
Since you tagged this with wtforms, I'll give you an example of how you could be doing this.
Never have this issue again
The WTForms' documentation has an example class that will create a list of checkboxes for you:
class MultiCheckboxField(SelectMultipleField):
"""
A multiple-select, except displays a list of checkboxes.
Iterating the field will produce subfields, allowing custom rendering of
the enclosed checkbox fields.
"""
widget = widgets.ListWidget(prefix_label=False)
option_widget = widgets.CheckboxInput()
You would use this field in your custom form in this manner:
class FriendsForm(Form):
potential_friends = MultiCheckboxField("Friends", coerce=int)
# ... later ...
#app.route("/add-friends", methods=["GET", "POST"])
def add_friends():
form = FriendsForm(request.form)
# lookup friends, for now we'll use a static list
form.potential_friends.choices = [(1, "Sam"), (2, "Joe")]
# We'll also need a mapping of IDs to Person instances
# (Made up for this example - use your own ;-) )
mapping = {
1: Person("Sam", profile_pic="sam.jpg"),
2: Person("Joe", profile_pic="joe.png")
}
if request.method == "POST":
# Mark new friends
return render_template("friends.html", form=form, persons=mapping)
Then, in friends.html you can iterate over the form.potential_friends field:
{% for person in form.potential_friends %}
persons[person.data].profile_pic :: {{person.label}} :: {{person}}<br>
{% endfor %}
You can customize your HTML inside the for loop. My particular example should render (with a few more attributes, like for and name):
sam.jpg :: <label>Sam</label> :: <input type="checkbox" value="1">
joe.png :: <label>Joe</label> :: <input type="checkbox" value="2">
I personnally would add a hidden input field in your fieldset under each checkbox with a name such as "friend_nametag1" and a value corresponding to the friend's ID. With the 1 being incremented for every "friend". You can thus look it up in flask view using something like
friend_list = []
list_of_checkboxes = ... (fetch from request.form... ?)
dict_of_friend_nametags = ... (build from request.form... ?)
if 'checkbox1' in list_of_checkboxes:
friend_list.append(dict_of_friend_nametags.get('friend_nametag1')
Obviously you can use some sort of logic to have an incremental index (the "1" in "checkbox1" in this case).
I'm not too familiar with WTForms so there might be a better way to do this, but this solution is fairly straightforward to implement with your current code.
If you want a FieldSet or FormSet I would suggest you use the FormField in conjunction with the FieldList with the related docs here : http://wtforms.simplecodes.com/docs/dev/fields.html#field-enclosures
p.s.: I would not recommend using request as a variable name in your template or your code as it may shadow the global request of flask ? XD

How do I get the value of a BoundField in a django template?

The built in as_html, as_ul, as_p methods on Django forms don't work for me, nor does the built in {{field}} rendering, so I'm trying to write a custom form rendering.
Here's what I have so far:
<input id="id_{{field.html_name}}"
type="text"
name="{{field.html_name}}"
placeholder="{{field.label}}" <!-- "placeholder" is really the only reason I need to do a custom implementation -->
value="{{ XXX }}" <!-- what goes here? -->
maxlength="30" />
The question is, what should go in the value attribute (marked XXX above)?
I've done some looking around and it doesn't appear that BoundField supports a value or data attribute. I'm using ModelForms if it matters
Assuming the field name is "username" and the form name is "user_form", there are two values:
1) Initial:
{{ user_form.initial.username }}
2) Bound:
{{ user_form.username.data }}
The value attribute landed in trunk in 2010. The patch shows how to retrieve the value using the form/data (not simple in a template unfortunately). There are some template tag code snippets in the ticket comments you may find useful.
I tried to find an answer for this question for several hours. The above answer didn't help me.
I found the solution here:
http://djangosnippets.org/snippets/2264/
You need to add new directory: /yourproject/yourapp/templatetags/
In /yourproject/yourapp/templatetags/ place 2 files:
__init__.py - empty file
field_value.py - with the following code:
from django import template
register = template.Library()
#register.simple_tag
def field_value(field):
""" returns field value """
return field.form.initial.get(field.name, '')
At the beginning of your template you nedd to add:
{% load field_value %}
Where you want to output a value of a field you need to add:
{% field_value form.field %}
Or if you already have a "field" variable, then just:
{% field_value field %}
For me it was a field with name "text" of an inline form, so I added the following code
{% field_value inline_admin_form.form.text %}