wagtail formbuilder show 'required' in template - python

I am implementing a Formbuilder form in a wagtail website, but like to get the required value while looping over the form fields so I can show a required icon. The required seems to be in the query, but nothing I try shows me a result.

Create a loop through form
django doc
{% for field in form.visible_fields %}
<div>
<div class="form-group">
{{ field.errors }}
{{ field.label_tag }}
<input type="{{ field.field.widget.input_type }}" class="form-control"
name="{{ field.name }}" id="{{ field.id_for_label }}"
{% if field.field.required %}required="required"{% endif %}>
{% comment %}you might want form field for textarea or select etc. just make conditions for those {% endcomment %}
</div>
</div>
{% endfor %}

Wagtail form builder generates a normal Django form, so your best bet for custom styling is to explore how to style Django forms first.
I would recommend Django Crispy Forms as I have used it to customise how fields are presented and it worked well.
Their docs have a specific mention about how to override how required fields are rendered.
https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html#change-required-fields
Otherwise you could just use some custom CSS to put the icon where you need it for fields with the required attribute.
https://developer.mozilla.org/en-US/docs/Web/CSS/:required

Related

How Do I Render Form Attributes Manually in Django?

I am trying to render the name attribute manually.
{% for language in form.languages %}
<div class="form-check">
<input class="form-check-input" id="{{ language.id_for_label }}" name="{{ language.field.name }}" type="checkbox">
<label class="form-check-label" for="{{ language.id_for_label }}">{{ language.choice_label }}</label>
</div>
{% endfor %}
Everything gets rendered nicely except the name attribute of the input tag.
form.languages is a ManyToManyField shown on my form as a ModelMultipleChoiceField using the following code in my forms.py.
languages = forms.ModelMultipleChoiceField(
queryset=Language.objects.all(),
widget=forms.CheckboxSelectMultiple
)
EDIT: Found the culprit, apparently I need a value attribute, not a name attribute, now I just need to find a way to get the value into the template.
I fixed the issue. What I did was use {{ language.data.value }}.

Did you forget to register or load this tag in Django?

In the django project I am working on, when I add this line {% set alpha = SafeExec.objects.get(testcase=a_test) %} to my html, it is showing this error. How to get rid of it?
This is my template code:
{% for a_testcases in testcases %}
<li><i>{{ a_testcases.0.program.name }}</i> <br/>
{% for a_test in a_testcases %}
{% set alpha = SafeExec.objects.get(testcase=a_test) %}
{{ alpha.cpu_time }}
{% endfor %}
<input id="id{{ a_test.id }}" type="checkbox" name="testcases_cbx" value="{{ a_test.id }}" checked/>
<label style="display: inline" for="id{{ a_test.id }}">{{ a_test.name }}</label> <br/>
{% endfor %}
This is screenshot of error:
Use "with" tag if you want to create any variable in django template.
check this answer
How to set a value of a variable inside a template code?
You can't do any of this in the template. set isn't a template tag; SafeExec won't exist in the context; and you can't call methods with arguments in templates anyway.
Without seeing your models I can't tell exactly what you need to do, but it looks like the testcase has a foreign key to SafeExec, so you should just do:
{{ a_test.safeexec.cpu_time }}

Looping through Django Templates

I want to change the classes / attributes of the input fields of a ModelForm, but I'd like to do it from the template if possible.
Below is my solution for this, using the django django-widget-tweaks
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
{{form.title|add_class:"form-control"|attr:"placeholder:Title"|attr:"type:text"}}
</div>
<div class="form-group">
{{form.description|add_class:"form-control"|attr:"placeholder:Description"}}
</div>
<div class="form-group">
{{form.author|add_class:"form-control"|attr:"placeholder:Author"}}
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value="Submit" />
</div>
</form>
My problem, is that this isn't very DRY, and I'm wondering if there's a better way to do this. I know django has looping over forms, but I'm not sure how I can integrate it while modifying the attributes.
Any help is appreciated.
You can take the placeholder and store it inside the field's help_text field. With that out of the way, you can easily loop through the fields like so:
{% for field in form %}
<div class="form-group">
{{ field|add_class:"form-control"|attr:field.help_text }}
</div>
{% endfor %}
Unfortunately it's hard/impossible to use a filter as for the second argument, so you will need to set help_text to 'placeholder:%s' where %s is your desired value.
If you're using a regular form, then set help_text in the constructor. But if you're using model form, I think it would be best to create a new template tag that can create the 'placeholder:%s' string for you from the field title:
#register.assignment_tag
def get_placeholder_arg(field):
return 'placeholder:%s' % field.label
Then your code would look like this:
{% for field in form %}
{% get_placeholder_arg field as arg %}
<div class="form-group">
{{ field|add_class:"form-control"|attr:arg }}
</div>
{% endfor %}
See the django documentation on custom template tags for details.

How to customize the rendering of a form in Django?

I've been avoiding using forms in Django for a while now because of this, and I feel like it is probably bad practice. When rendering forms in Django, everything is automated. This stops you from being able to conditionally render or hide certain parts of the form, attach different css classes to that form, etc.
What is the correct way to use Django forms in as dynamic a fashion as possible?
I'm in the same boat as you Jim, and I'm currently looking at https://docs.djangoproject.com/en/dev/ref/forms/widgets/. It seems a good starting point for customisation of fields.
As for conditionally showing/hiding elements, if you want this to be done on the form load (ie, a predetermined form layout, you could follow this SO answer which explains changes to the form's init: Conditionally show and hide a form field and set the field value
Or, if you mean how you could do this contextually depending on other selections as the form is being completed, the only way I've found up to now is to have some custom jQuery loaded in with the template that the form renders on. If there's a way to do this in-form, I want to know too :)
First of all, absolutely don't avoid forms. In fact, always use forms in django. They're simple to use and there's no reason not to.
Forms have enough flexibility to give you as much control as you need.
Typically you'll want to do something like this:
<form action="/myurl/" method="post">
{% csrf_token %}
{% for fld in form %}
{{ fld.label }} {{ fld }} {{ fld.help_text }} {{ fld.error }}
{% endfor %}
<input type="submit" value="Submit" />
</form>
You also might want to wrap fields in divs or a table. You might also test for fld.name to do something custom based on a field name.
Basing my answer on what Rainy has and referring to this and this, my answer would be
sudo pip install django-widget-tweaks
To enable widget_tweaks in your project you need to add it to INSTALLED_APPS in your projects settings.py file:
INSTALLED_APPS = [
...
'widget_tweaks',
...
]
I'd include this at the beginning of all the template files that I have forms to render.
{% load widget_tweaks %}
And render my forms as follows:
<form method="post" action="">
{% csrf_token %}
{% for fld in form %}
<div class="form-group">
{% for error in fld.errors %}<p class="help-block text-danger">{{ error }}</p>{% endfor %}
<label>{{ fld.label }}</label>
{% render_field fld class+="form-control" %}
<p class="help-block">{{ fld.help_text|safe }}</p>
</div>
{% endfor %}
<button type="submit" class="btn btn-success">{% trans 'Submit' %}</button>
</form>

How to extend the comments framework (django) by removing unnecessary fields?

I've been reading on the django docs about the comments framework and how to customize it (http://docs.djangoproject.com/en/1.1/ref/contrib/comments/custom/)
In that page, it shows how to add new fields to a form. But what I want to do is to remove unnecesary fields, like URL, email (amongst other minor mods.)
On that same doc page it says the way to go is to extend my custom comments class from BaseCommentAbstractModel, but that's pretty much it, I've come so far and now I'm at a loss. I couldn't find anything on this specific aspect.
I recently implemented the solution that Ofri mentioned, since I only wanted to accept a solitary "comment" field for a comment (like SO does, no "name", no "email" and no "url").
To customize the default comment form and list display, I created a "comments" directory in my root "templates" directory and overrode the two default comment templates.
My "/templates/comments/form.html" is:
{% load comments i18n %}
{% if user.is_authenticated %}
<form action="{% comment_form_target %}" method="post">
{% csrf_token %}
{% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.name != "name" and field.name != "email" and field.name != "url" %}
{% if field.errors %}{{ field.errors }}{% endif %}
<p {% if field.errors %} class="error"{% endif %} {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}>
{{ field }}
</p>
{% endif %}
{% endif %}
{% endfor %}
<input type="submit" name="post" class="submit-post" value="{% trans "Add Comment" %}" />
</form>
{% else %}
I'm sorry, but you must be logged in to submit comments.
{% endif %}
Which is only slightly different from the default comments form, primarily suppressing the display of the not-required "name", "email" and "url" inputs.
My "/templates/comments/list.html" is:
<div class="comment_start"></div>
{% for comment in comment_list %}
<div class="comment">
{{ comment.comment }}
(from {{ comment.user }} - {{ comment.submit_date|timesince }} ago)
</div>
{% endfor %}
On the page I want the form, I first call {% load comments %} and then {% render_comment_form for [object] %} to show the form, or {% render_comment_list for [object] %} to generate a list of the comments on the object (replace [object] with your appropriate object name).
This is working great for me, and still giving me all the other "free" stuff that comes with django comments (moderation, flagging, feeds, polymorphic associations, etc...)
A tidy summary of how to do this elegantly, through the actual comments framework subclassing approach, rather than hiding elements in a form/other untidy hacks, can be found Django Comments: Want to remove user URL, not expand the model. How to?
Essentially, you subclass the CommentForm, and change its get_comment_create_data(self) method, and then pop out the attributes you don't want (e.g. email, url, etc.)
J
You can try overriding the comment form with a custom template that only shows the fields you want.

Categories