Using Bootstrap5, Django and Crispy Forms to create a calculator application.
Application works as expected however I want to make changes to the appearance of the forms.
I've already removed the required field asterisk by simply adding the following to the CSS file:
.asteriskField {
display: none;
}
But now I want to place the label inside the field which requires a different approach that I'm currently unable to understand despite extensive research.
Having used Inspect in Chrome I can see that the label is of course a separate element but one housed within the field to achieve the given effect.
Current Form
Desired result
Settings.py (excerpt)
CRISPY_TEMPLATE_PACK = 'bootstrap5'
Forms.py (excerpt)
class InvestmentForm(forms.Form):
starting_amount = forms.ChoiceField(choices=STARTING_AMOUNT)
deposit_amount = forms.FloatField()
trade_in_value = forms.FloatField()
number_of_years = forms.FloatField()
credit_score = forms.ChoiceField(choices=CREDIT_SCORE)
state = forms.ChoiceField(
label='State',
choices=[(zipcode, zipcode) for zipcode in StateTax.objects.values_list('zipcode', flat=True).distinct()]
)
Index.html (excerpt)
<div class="row justify-content-center">
<h5 class="text-center"> Enter details below to see your estimate</h5>
</div>
<div class="col-md-8 mx-auto">
<form action="" method="POST">
{% csrf_token %}
{{ form|crispy }}
<br>
<button class="btn btn-primary" type="submit">Calculate</button>
</form>
<br>
</div>
</div>
You could use crispy-bootstrap5 which introduces floating labels. Just follow the installation guidelines and add a floating input field in your crispy Layout like:
FloatingField("first_name"),
Related
I am rendering a model form in Django using {{ form.as_div }}
It is rendering as expected as I want each field wrapped in a div.
I would now like to add a class to this auto generated div.
adding widgets in the forms.py file only adds attribute to the input field itself and not the div around the field.
Can someone point me in the right direction to add attributes to the div instead of the input field?
{{ form.as_div }} is not possible in Django but, you can do like this
====== in views.py =========
def DemoView(request):
form = StudentForm()
context = {'form':form}
return render(request,'demo.html',context)
======= in html file ========
<h1>Student Form</h1>
<form action="" method="get" >
{% for fm in form %}
<div>
<label>{{fm.label}}</label>
<p>{{fm}} </p>
</div>
{% endfor %}
</form>
======= Output =========
since django 4.1 you can use "as_div"!
I myself need this possibility in an earlier Version so i built myself an abstract Formclass containing my version of "as_div" derived from the existing render-functions:
class DivRenderer():
"""
as_div: abstract class
"""
def as_div(self):
"Return this form rendered as HTML <divs>s - according to client-Layout."
return self._html_output(
normal_row='<div class="form-group input" %(html_class_attr)s> %(errors)s%(field)s%(help_text)s %(label)s</div>',
error_row='<div%s</div>',
row_ender='</div>',
help_text_html='<br><span class="helptext">%s</span>',
errors_on_separate_row=False,
)
pass
and than using it simply while defining my forms like:
class someThingForm(forms.ModelForm, DivRenderer):
readonly = …
…
and than just using {{ form.as_div }} in the Templates
However!: The as_div-function is different as the one from 4.1 - so be careful not to expect the same behaviour!
hope it helps
Karl
I made a form with the FormBuilder of Symfony.
When I put my form in twig, the form_start(form) and form_end(form), it add a tag for each input.
I don't understand why twig adds a tag.
What is the solution to remove this tag
Thanks for your answer :)
Also, my formbuilder is like that :
->add('title', TextType::class, array(
'label'=>false,
'attr'=>array('autofocus'=>true)
))
my twig is like that :
{{ form_start(form) }}
<div class="row">
<div class="col-sm-9 p-1">
{{ form_row(form_record.title, {'attr':{'class':"form-control", 'placeholder':"Description"|trans, 'title':"Description"|trans }}) }}
{{ form_errors(form_record.title) }}
</div>
<div class="col-sm-1 pt-2">
<button type="submit" class="btn btn-success btn-circle btn-sm">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
{{ form_end(form) }}
and the result in the html source code is :
<div class="row">
<div class="col-sm-9 p-1">
<div>
<input type="text" id="app__title" name="app_[title]" required="required" class="form-control" placeholder="Description" title="Description">
</div>
</div>
</div>
So Twig add the
<div>
that I don't want. How can I remove this autocompleted tag?
I tried the
{% do form_record.title.set rendered %}
but maybe I think that it does not work.
Edit: Okay it seems I misunderstood the issue at first.
I thought you wanted to hide a field you had in your form which can be done with
{% do form.myField.setRendered %}
Now that I understand the issue, I believe it comes from the way your field is being printed.
There are 3 main components to a form field.
Label: form_label(form.field)
Widget: form_widget(form.field)
Errors: form_errors(form.field)
There is a way to print all three components at once. The function is
form_row(form.field)
Here comes the culprit: form_row(). Because it normally prints 3 different components, it adds a div around it!
Futhermore, by looking at the form type and seing 'label' => false, I can say that the label was printing at first using form_row.
To avoid having to define 'label'=>false everytime, you can simply print your form field in this manner:
{{ form_widget(form_record.title, {'attr':{'class':"form-control", 'placeholder':"Description"|trans, 'title':"Description"|trans }}) }}
{{ form_errors(form_record.title) }}
You can simply omit {{form_label(form_record.title)}} and it won't print.
On the other hand, I also noticed something that might be okay but seem wrong with the given example.
In the twig you shared, the form starts with {{ form_start(form) }} but then the field is {{ form_row(form_record.title)}}.
From where I come from form_record is undefined here. I would use {{ form_row(form.title)}}
Anyways, the explanation for the difference between form_row and form_widget can be found here: Symfony form differences between row and widget
Enjoy!
As part of a Django project, I have created the following in the views.py file
def profile(request):
u_form =UserUpdateForm()
p_form =ProfileUpdateForm()
context={
'u-form': u_form,
'p-form': p_form
}
I am now trying to render these forms on the html page (profile.html) with the following code:
{% extends "socialmedia/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
</div>
</div>
<form method="POST" enctype="multipart/form-data>
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Information</legend>
{{u_form|crispy}}
{{p_form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update....</button>
</div>
</form>
</div>
{% endblock content %}
Everything else is rendering on the page correctly, except for this bit:
{{u_form|crispy}}
{{p_form|crispy}}
There are no errors on running the server, so I am finding it hard to trouble shoot.
The code in the forms.py file is as follows:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class UserRegisterForm(UserCreationForm): #form that inherits from the usercreationform
email = forms.EmailField()
class Meta:
model = User
#when this form validates it creates a new user
#type the fields to be shown on your form, in that order.
fields = ['username','email','password1','password2']
"""this gives us a nested name space for configurations and
keeps the configs in one place. The model that will be affected is
the user model e.g. when we do a form.save it saves it to the user model.
And the fields we have are the fields we want on the form. It shows order too.
"""
#create a model form...this allows us to create a form that#works with a specific database model#
#we want a form that works with our user model
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model= Profile
fields=['image']
My question is:
Could someone tell me why these additional fields (username, email and image update) are not being shown on the profile html above the 'update' button? In what file have I made the mistake. Note: I'd also appreciate an explanation of the rendering of these u-forms, along with the solution(pointing out my error). I understand that u-form is an instance of UserUpdateForm, but not much else.
context={
'u-form': u_form,
'p-form': p_form
}
You just have a typo. Change the - to _
Because I am not from English Naive country.
Default html content from Django form, is not suitable for my country.
Could someone tell me how to edit html content in forms.py?
I just want to keep English variable for later SQL column settings, but change html content in form.
in forms.py
class DjUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = DjUser
fields = ('username', 'email', 'password')
in html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
<input type="submit" value="註冊">
</form>
It showed all English content in html, like Username, Email Address etc..
The thing I needed is 使用者名稱, 電子信箱 etc.. The html contents I want to edit:
You can use attr for styling and naming you're form fields, it will go something like this:
class DjUserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput(attrs={
'class': 'my-class',
'placeholder': '使用者名稱, 電子信箱',
}))
also you will perhaps need to do some localization for you're application.
I have a "GET" / "POST" split on my html page courtesy of a python flask script:
def home(name=None):
if request.method == "GET":
return render_template('home.html', name=name)
if request.method == "POST":
files = request.form["file[]"]
do things with the files
On my home.html page, I have added in some bootstrap code to make everything pretty, but the flask module is now not taking in the form data properly. Here's my html code:
<form id="uploadbanner" enctype="multipart/form-data" method="post" action="{{ url_for('home') }}">
<div class="form-group">
<div class="container">
<div class="page-header">
<br>
<h1>Title</h1>
<br>
<br>
</div>
<div class="row">
<div class="col-lg-6 col-md-6 col-s-6 col-xs-12">
<h4>File Control</h4>
<div class="jumbotron">
And my form data is here:
<input type="file" name="file[]" id="inputnameid" multiple=""/>
</div>
</div>
Second Column
</div>
New Row, etc etc
Each new row has buttons and inputs that I want to match with the form data using the name field.
I know I'm not structuring this properly, but I can't seem to find any info on how to mesh bootstrap and forms.
I think in order to get the files, you should use request.files["file[]"] instead of request.form["file[]"] .