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.
Related
I am having a problem with Django forms. I am currently using the request.POST to validate the POST within views.
I want to send inputed-data(radio type) from my template with the same name.
In my template.py:
<form method="post" action="{% url 'app:AnsSubmission' %}">
{% csrf_token %}
{% for i in Exam %}
<div class="form-group col-xl-12">
<label>{{ i.question }}</label>
<div class="radio">
<label><input type="radio" class="mx-2" name="givenAns" array_column="{{ i.pk }} value="True" required>True</label>
</div>
<div class="radio">
<label><input type="radio" class="mx-2" name="givenAns" array_column="{{ i.pk }} value="False" required>False</label>
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
And willing to fetch these data in views.py like:
givenAns_list = request.POST.getlist('givenAns')
for i in givenAns_list:
this_givenAns = givenAns_list[i]
But the problem here is this radio type input field doesn't take value for the same name(not as a list I wish). If I select answer of 2nd question, the 1st one's selection is unselected.
Please suggest how can I fix this?
I am trying to use Django provided forms instead of manually creating them with HTML. When I do this, however, they do not appear. The questions/answers I have found on this site have so far been unable to solve my issue. (unless I am reading them wrong.)
forms.py
from django import forms
class KeywordForm(forms.Form):
input_keywords = forms.CharField(label="Keywords", max_length='100')
class LocationForm(forms.Form):
input_location = forms.CharField(label="Location", max_length="250")
views.py
from django.shortcuts import render
from .forms import KeywordForm, LocationForm
def search_view(request):
keyword_form = KeywordForm()
location_form = LocationForm()
return render(request, 'search_results.html', {'keyword_form': keyword_form, 'location_form': location_form})
urls.py
from django.urls import path
from . import views
urlpatterns = [
...
path('search/', views.search_view, name='search'),
]
base.html
{% block search %}
<div class="card">
<div class="card-body">
<form class="row align-items-center">
<form action="search" method="GET">
<div class="col-sm-2">
{{ keyword_form }}
</div>
<div class="col-sm-2">
{{ location_form }}
</div>
<!-- <label for="inputKeywords" class="form-label">Keywords</label>-->
<!-- <input class="form-control" id="inputKeywords" type="text" name="inputKeywords" placeholder="Enter Keywords...">-->
<!-- </div>-->
<!-- <div class="col-sm-2">-->
<!-- <label for="inputLocation" class="form-label">Location</label>-->
<!-- <input type="Text" class="form-control" id="inputLocation" name="inputLocation" placeholder="Enter location...">-->
<!-- </div>-->
<div class="col">
<input class="btn btn-primary" type="submit" value="Search">
</div>
</form>
</form>
</div>
</div>
{% endblock %}
Per request: search_results.html, which isn't finished due to the forms not showing up in base.html.
{% extends 'base.html' %}
{% block search %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="navbar-nav">
<form action="search" method="GET">
{{ keyword_form }}
{{ location_form }}
<input class="btn btn-primary" type="submit" value="Search">
</form>
</div>
</nav>
{% endblock %}
In base.html replace this:
{% block search %}
<div class="card">
<div class="card-body">
<form class="row align-items-center">
<form action="search" method="GET">
<div class="col-sm-2">
{{ keyword_form }}
</div>
<div class="col-sm-2">
{{ location_form }}
</div>
<div class="col">
<input class="btn btn-primary" type="submit" value="Search">
</div>
</form>
</form>
</div>
</div>
{% endblock %}
with this:
{% block search %}
{% endblock search %}
Let me see if i can explain clearly what's happening here..
You created a view for search_results.html so when you render that page the view passes the context variable to it, which includes the forms. All good 'till here.
From the code you shared i see that then you went ahead and added the Django Template Language to render those forms directly in base.html. But that won't work because base.html doesn't have access to the context variable you're passing to search_results.html.
When you extend a template and you add content within blocks that are present in the parent template, what happens is that the block in question is overwritten.
So in your case, whatever you're writing between search blocks in base.html will be wholly overwritten by what's in between those same blocks in search_results.html.
From what i see there are no errors in the code so I think all you have to do is to work on your search_results.html template. And when you test if it works or not do so on search_results.html, not anywhere else, because that's the template that will have access to the context dictionary.
The problem might also be that for some reason those form elements are empty, or that something is wrong at some other step of the way. The template doesn't mind being passed empty context variables so you should also consider that maybe the forms are being passed to the template but they're just empty. You have to run little tests for these things. Try passing a variable containing a simple string to the template and try to render that. Does it work? Good, at least you know that the problem is somewhere else. Doesn't it? Even better, you're one step closer to the solution.
How can I add attribute autocomplete="off" to the input login template form for an admin?
I'm find this in the login.html template but can't find where is the form template
<div class="form-row">
{{ form.username.errors }}
{{ form.username.label_tag }} {{ form.username }}
</div>
If you need to change behavior based on whether or not the user is admin/staff:
{% if request.user.is_staff %}
<form autocomplete="off" method="post" action="action_name">
<input autocomplete="off" name="hidden" type="text" style="display:none;">
{% else %}
<form method="post" action="action_name">
{% endif %}
<div class="form-row">
And complete the rest of the form as you would.
Reference for the form and input tags to turn autocomplete off (note autocomplete is "off" in the input tag as per testing in comments):
https://gist.github.com/niksumeiko/360164708c3b326bd1c8
I'm trying to create custom template for Django's build-in login view. At the moment it looks like (registration/login.html):
<form method="post">
{% csrf_token %}
{% for field in form %}
{% include 'registration/form_field.html' %}
{% endfor %}
<input class="btn btn-primary btn-block" type="submit" value="{% trans "Log in" %}">
</form>
And registration/form_field.html file is:
<div class="form-group {% if field.errors %}has-error{% endif %}">
<input class="form-control" name="{{ field.name }}" placeholder="{{ field.label }}" {% if field.data %}value="{{ field.data }}"{% endif %} />
{% if field.errors %}
<span class='text-danger'>{{ field.errors|join:'<br>' }}</span>
{% endif %}
</div>
Everything works as expected, only problem is that password is shown in clear text.
To solve this type="password" should be set for password field (and type="text" for username field).
Is it possible to implement this using field variable (i.e. something like {{ field.type }})?
You can implement a PasswordInput widget in your form definition, that will render as a password field with type="password".
class ExampleForm(forms.Form):
password = forms.CharField(label='Password',
widget=forms.PasswordInput())
In the templates,
{{form.password}}
will render this field, which is the cleanest solution.
You may also access the type of the field (as you wanted), like this:
{{form.fields.password.widget.input_type}}
Note that if you'd like further customization beyond simply rendering the form, there's nothing wrong with just writing your own html for the fields.
I am trying to use the include Django template tag, and inside it I reference a template which handles the format of the form. When I reference this though inside my template it outputs each of the dynamic parts, each character per new line, it is really strange. For example here is a snippet of the output:
<form action="/admin/events/create_submit/" method="post">
<div class="fieldWrapper">
: <
</div>
<div class="fieldWrapper">
: l
</div>
<div class="fieldWrapper">
: i
</div>
<div class="fieldWrapper">
: >
</div>
...
EXPECTED OUTPUT
<form action="/admin/events/create_submit/" method="post">
<div class="fieldWrapper">
<li><label>field</label><input type="text" /></li>
</div>
...
I realise the markup on the li inside the div is incorrect but I am trying to understand why the html is being encoded and each character split into a new line inside the template div and prefixed with the colon ":"
The template which I am trying to render is this:
<form action="{{action}}" method="post">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Submit" /></p>
</form>
And I reference the include template like this:
{% include "forms/form_template.html" %}
Does anyone know or could help m as to why this would be causing each dynamic piece to output per character on each line?
TIA
Andrew
form is probably a string rather than a Form object, and iterating over a string yields its individual characters.
spaceless tag
Removes whitespace between HTML tags. This includes tab characters and newlines.