Django Boostrap TimePicker/Forms not working - django

I am working on a project and have ran into an issue with my forms. In particular, I want the form to use Bootstrap4 (from CDN) elements, yet when I try to use the widgets feature of ModelForm, it isn't working quite right
forms.py:
class Meta(object):
model = ScheduleItem
fields = (
'name',
'time_start',
'time_end',
'day',
)
widgets = {
'name': forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'test'
}
),
'time_start': forms.TimeInput(
attrs={
'class': "form-control"
}
)
}
def __init__(self, *args, **kwargs):
super(ScheduleItemForm, self).__init__(*args, **kwargs)
self.fields['name'].label = ""
self.fields['time_start'].label = ""
self.fields['time_end'].label = ""
self.fields['day'].label = ""
html page: (The first two are ones using the form and the latter are not using it)
<form action="" method="POST">
{% csrf_token %}
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupSelect01">Description</label>
{{schedule_item_form.name|as_crispy_field}}
</div>
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupSelect01">Start Time</label>
{{schedule_item_form.time_start|as_crispy_field}}
{% comment %} <input type="time" class="form-control" aria-label="Username" name="start_time" required> {% endcomment %}
</div>
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupSelect01">End Time</label>
<input type="time" class="form-control" aria-label="Username" name="end_time" required>
</div>
<div class="input-group mb-3">
<label class="input-group-text" for="inputGroupSelect01">Day of the Week</label>
<select class="form-select" id="inputGroupSelect01">
<option selected>Choose...</option>
<option value="0">Monday</option>
<option value="1">Tuesday</option>
<option value="2">Wednesday</option>
<option value="3">Thursday</option>
<option value="4">Friday</option>
<option value="5">Saturday</option>
<option value="6">Sunday</option>
</select>
</div>
<button type="submit" class="btn btn-primary mb-2 mt-2">Add item to schedule</button>
</form>
Output:
HTML Output
Preferably, I would like all the inputs to look akin to the bottom two. Why does my form look so wacky? Thank you!

What I did to fix this was remove the {{|as_crispy_field}} as it was clashing with the 'form-control' tag in the widgets in my form

Related

Django: unable to define initial values of Form

I have the following form:
class UpdateForm(forms.Form):
name = forms.CharField(max_length = 15,
widget=forms.TextInput(
attrs={
"class": "form-control",
'required': True,
'placeholder': 'Device name'
}
))
turn_server = forms.ChoiceField(
choices = TURN_CHOICES,
widget=forms.Select(
attrs={
"class": "form-control form-control-sm",
}
))
fps = forms.IntegerField(
widget=forms.NumberInput(
attrs={
'id':'ex1',
'data-slider-id':'ex1Slider',
'type':"text",
'data-slider-min':"10",
'data-slider-max':"60",
'data-slider-step':"1",
}
))
bitrate = forms.IntegerField(
widget=forms.NumberInput(
attrs={
'id':'ex2',
'data-slider-id':'ex2Slider',
'type':"text",
'data-slider-min':"200",
'data-slider-max':"2000",
'data-slider-step':"1",
}
))
class Meta:
model = Device
fields = ['name','fps','bitrate','turn_server']
to be used in the HTML template:
<form action="." method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form-group row{% if field.errors %} invalid{% endif %}">
<label class="col-sm-3 col-form-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
<div class="col-sm-6">
{{ field }}
{% for error in field.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-sm btn-light">Save</button>
</form>
and the view.py:
def control(request):
template = 'template.html'
context = {}
context['form'] = UpdateForm(initial={
'name': 'TestName',
'fps': '45',
'turn_server':'TestServer',
'bitrate':'500'
})
return render(request, template, context)
For some reason I can't figure it out, the form rendered in the template does not render with the initial values I have defined with initial. For example the fps resulted input html element is the following:
<input type="text" name="fps" value="10" id="ex1" data-slider-id="ex1Slider" data-slider-min="10" data-slider-max="60" data-slider-step="1" required="" data-value="10" style="display: none;">
Oddly, If I print in the views.py the form that is passed to the context I get the correct form data (ex value=45):
<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" value="TestName" class="form-control" required placeholder="Device name" maxlength="15" id="id_name"></td></tr>
<tr><th><label for="id_turn_server">Turn server:</label></th><td><select name="turn_server" class="form-control form-control-sm" id="id_turn_server">
<option value="1">frankfurt</option>
<option value="2">amsterdam</option>
<option value="3">new_york</option>
</select></td></tr>
<tr><th><label for="ex1">Fps:</label></th><td><input type="text" name="fps" value="45" id="ex1" data-slider-id="ex1Slider" data-slider-min="10" data-slider-max="60" data-slider-step="1" required></td></tr>
<tr><th><label for="ex2">Bitrate:</label></th><td><input type="text" name="bitrate" value="500" id="ex2" data-slider-id="ex2Slider" data-slider-min="200" data-slider-max="2000" data-slider-step="1" required></td></tr>
You can try to define the initial data from the form:
name = forms.CharField(initial='Your name')
Take a look at the documentation here

Django selected value using manual render form in django

I'm trying to implement CRUD operations in django, however, I'm stuck in the edit operation.
After passing the data to edit template I need to show the selected values of operating system dropdown list, how can I achieve that?
I utilized the manual rendering of django form with the following code in the template:
<div class="form-group row">
<label class="col-sm-3 col-form-label">Operating System</label>
<div class="col-sm-9">
<select class="form-control" name="os_id" id="os_id" required>
<option value="">--Select--</option>
{% for os in os %}
<option value="{{ os.id}}">{{ os.key_name}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Title</label>
<div class="col-sm-9">
<textarea class="form-control" id="title" name="title" rows="3" required>{{ servicedesk.title }}</textarea>
</div>
</div>
here's the view code:
def edit(request, id):
servicedesk=Servicedesk.objects.get(id=id)
softwares=Software.objects.all
os=OperatingSystem.objects.all
context = {'servicedesk':servicedesk, "softwares":softwares, "os":os}
return render(request, 'servicedesks/edit.html', context)
and the model:
class OperatingSystem(models.Model):
key_name = models.CharField(max_length=100,null=True)
key_description = models.CharField(max_length=255,null=True)
class Meta:
db_table = "operating_systems"
def __str__(self):
return self.key_name
class Software(models.Model):
key_name = models.CharField(max_length=100,null=True)
key_description = models.CharField(max_length=255,null=True)
class Meta:
db_table = "softwares"
def __str__(self):
return self.key_name
class Servicedesk(models.Model):
os_id=models.ForeignKey(OperatingSystem, on_delete=models.SET(0))
software_id = models.ForeignKey(Software, on_delete=models.SET(0))
title = models.CharField(max_length=255,null=True)
I tried this but it's not working:
<div class="form-group row">
<label class="col-sm-3 col-form-label">Operating System {{os_id}}</label>
<div class="col-sm-9">
<select class="form-control" name="os_id" id="os_id" required>
<option value="">--Select--</option>
{% for os in os %}
{% if os.id == servicedesk.os_id %}
<option value="{{os.id}}" selected>{{os.key_name}}</option>
{% endif %}
<option value="{{ os.id}}">{{ os.key_name}}</option>
{% endfor %}
</select>
</div>
</div>

Django-crispy-forms change radio button error rendering

When an error is rendered for a non-radio button, I see this:
<div id="div_id_field_a" class="control-group error">
<label for="id_field_a" class="control-label ">Field A</label>
<div class="controls">
<select class="select" id="id_field_a" name="field_a">
<option value="" selected="selected"></option>
<option value="0">0</option>
<option value="1">1</option>
</select>
<span id="error_1_id_field_a" class="help-inline"><strong>Select one</strong></span>
</div>
</div>
When an error is rendered for a radio button, I see this:
<div id="div_id_field_b" class="control-group error">
<label for="id_field_b_0" class="control-label ">Field b</label>
<div class="controls">
<p id="error_1_id_field_b" class="help-block"><strong>Enter a value</strong></p>
<label class="radio"><input type="radio" name="field_b" id="id_field_b_1" value="True">Yes</label>
<label class="radio"> <input type="radio" name="field_b" id="id_field_b_2" value="False">No</label>
</div>
</div>
How can I get the error message to appear after the radio button controls, which is what happens when a combo box used? Or at least not render the error inside a p tag and instead a span tag?
Here's how I render the form:
{% load crispy_forms_tags %}
<form id='main-form'>
{% csrf_token %}
{% crispy form form.helper %}
</form>
and the form:
class MyForm(ReoBaseForm):
field_b = forms.ChoiceField(required=False, choices=((True, 'Yes'), (False, 'No')),
label='Field b', widget=forms.RadioSelect())
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False

field alignments in django crispy forms and bootstrap 3?

I am using django-crispy-forms and Bootstrap 3 in my template rendering.
Here is how my form looks like:
As you can notice, the fields are not aligned correctly. I want them to be inline. please provide suggestions on how to fix this:
My crispy form code is below:
class SortFieldsForm(forms.Form):
latest_year=forms.BooleanField(label="latest year")
newest_entry=forms.BooleanField(label="newest post")
price_order=forms.ChoiceField(
widget=forms.RadioSelect,
label="price order",
choices=(('lowest_price','lowest '),('highest_price','highest'),),
initial="lowest_price",
)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_class = 'form-inline'
self.helper.field_template='bootstrap3/layout/inline_field.html'
self.helper.form_method = 'post'
self.helper.form_action = '.'
super(SortFieldsForm, self).__init__(*args, **kwargs)
self.helper.layout = Layout(
InlineRadios('price_order'),
'newest_entry',
'latest_year',
Submit('submit', 'Submit', css_class='button white'),
)
And the generated HTML code:
<form action="." id="id-exampleForm" class="form-inline" method="post" >
<div id="div_id_price_order" class="form-group">
<label for="id_price_order" class="control-label requiredField">
price order
<span class="asteriskField">*</span>
</label>
<div class="controls ">
<label class="radio-inline">
<input type="radio" checked="checked" name="price_order" id="id_price_order_1" value="lowest_price" >lowest</label>
<label class="radio-inline">
<input type="radio" name="price_order" id="id_price_order_2" value="highest_price" >highest</label>
</div>
</div>
<div id="div_id_newest_entry" class="checkbox">
<label for="id_newest_entry" class=" requiredField">
<input class="checkboxinput checkbox" id="id_newest_entry" name="newest_entry" type="checkbox" />
newest post
</label>
</div>
<div id="div_id_latest_year" class="checkbox">
<label for="id_latest_year" class=" requiredField">
<input class="checkboxinput checkbox" id="id_latest_year" name="latest_year" type="checkbox" />
latest year
</label>
</div>
<input type="submit" name="submit" value="Submit" class="btn btn-primary button white" id="submit-id-submit"/>
</form>
This has nothing to do with crispy-forms itself, but rather that you have a label on the radio inputs that is pushing the actual inputs down. You need to add a margin-top style to div_id_newest_entry, submit-id-submit, and div_id_latest_year. For example (your use case may vary a bit), in your CSS file:
#div_id_newest_entry,
#div_id_latest_year,
#submit-id-submit {
margin-top: 25px;
}

Django inline formset : DELETE fied in form.visible_fields?

Maybe someone could explain this to me.
With the following models:
class ContactEmail(models.Model):
# Documentation
__doc__ = _(u'Stores an e-mail address for a contact.')
# Enums
CATEGORIES = (
(0, _(u'Personal')),
(1, _(u'Professional')),
)
# Attributes
category = models.IntegerField(choices=CATEGORIES, verbose_name=_(u'category'), help_text=_(u'This values indicates wheter the address is for personal or professional use.'))
email_address = models.EmailField(max_length=255, unique=True, verbose_name=_(u'e-mail address'), help_text=_(u'A valid e-mail address.'))
contact = models.ForeignKey('Contact', related_name=u'emails', verbose_name=_(u'contact'), help_text=_(u'The contact whose the e-mail address is.'))
priority_level = models.PositiveSmallIntegerField(verbose_name=_(u'priority level'), help_text=_(u'An integer used to define a priority level for e-mail addresses of a contact.'))
# Methodes
def __unicode__(self):
return u'%(mail)s' % {u'mail': self.email_address}
# Meta-data
class Meta:
verbose_name = _(u'E-mail')
verbose_name_plural = _(u'E-mails')
unique_together = ('contact', 'priority_level')
class Contact(models.Model):
pass
And the following ModelForms:
class ContactCreateForm(forms.ModelForm):
# Documentation
__doc__ = _(u'A custom form for Contact model.')
# Methods
def __init__(self, *args, **kwargs):
super(ContactCreateForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
if name != 'image':
if field.widget.attrs.has_key('class'):
field.widget.attrs['class'] += ' form-control'
else:
field.widget.attrs.update({'class':'form-control'})
# Meta-data
class Meta:
model = Contact
exclude = ['second_names', 'suffix', 'dob', 'skype_account',]
class ContactEmailCreateForm(forms.ModelForm):
# Documentation
__doc__ = _(u'A custom form for ContactEmail model.')
# Methods
def __init__(self, *args, **kwargs):
super(ContactEmailCreateForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
if field.widget.attrs.has_key('class'):
field.widget.attrs['class'] += ' form-control'
else:
field.widget.attrs.update({'class':'form-control'})
# Meta-data
class Meta:
model = ContactEmail
I'm trying to set up a create contact form that includes a formset for Emails (intention is to use django-dynamic-formset to dynamically adds form just like the Admin does - and actuall it works). Here's the view:
class ContactCreateView(LoginRequiredMixin, CreateView):
template_name = u'frontend/contacts/create.html'
model = Contact
form_class = ContactCreateForm
def get_context_data(self, **kwargs):
context = {
'emails' : inlineformset_factory(parent_model=Contact, model=ContactEmail, form=ContactEmailCreateForm, extra=1),
}
context.update(kwargs)
return super(ContactCreateView, self).get_context_data(**context)
django-dynamic-formset requires you to set can_delete=True which is set by default in inlineformset_factory. And this parameter adds a DELETE field to each form of your formset.
Until here, nothing to complain about. Except that it adds this fields to form.visible_fields which is, IMO, kind of disturbing since this field is hidden if there is no form.instance:
# create.html
<fieldset class="emails">
<legend>{% trans "E-mail(s)" %}</legend>
{{ emails.management_form }}
{% for form in emails %}
<div class="inline-form-emails">
{{ form.media }}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
<label for="{{ field.html_name }}" class="col-xs-12 col-sm-5 col-md-3 col-lg-3 control-label">
{{ field.label }} {% if field.field.required %}<span style="color: #a60000;">*</span>{% endif %}
</label>
<div class="col-xs-12 col-sm-7 col-md-9 col-lg-9">
{{ field }}
<span class="help-block">{{ field.help_text }}</span>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</fieldset>
As you can see the output:
<fieldset class="emails">
<legend>E-mail(s)</legend>
<input id="id_emails-TOTAL_FORMS" name="emails-TOTAL_FORMS" type="hidden" value="1"><input id="id_emails-INITIAL_FORMS" name="emails-INITIAL_FORMS" type="hidden" value="0"><input id="id_emails-MAX_NUM_FORMS" name="emails-MAX_NUM_FORMS" type="hidden" value="1000">
<div class="inline-form-emails dynamic-form">
<input id="id_emails-0-contact" name="emails-0-contact" type="hidden">
<input id="id_emails-0-id" name="emails-0-id" type="hidden">
<div class="form-group">
<label for="emails-0-category" class="col-xs-12 col-sm-5 col-md-3 col-lg-3 control-label">
Category <span style="color: #a60000;">*</span>
</label>
<div class="col-xs-12 col-sm-7 col-md-9 col-lg-9">
<select class="form-control" id="id_emails-0-category" name="emails-0-category">
<option value="" selected="selected">---------</option>
<option value="0">Personal</option>
<option value="1">Professional</option>
</select>
<span class="help-block">This values indicates wheter the address is for personal or professional use.</span>
</div>
</div>
<div class="form-group">
<label for="emails-0-email_address" class="col-xs-12 col-sm-5 col-md-3 col-lg-3 control-label">
E-mail address <span style="color: #a60000;">*</span>
</label>
<div class="col-xs-12 col-sm-7 col-md-9 col-lg-9">
<input class="form-control" id="id_emails-0-email_address" maxlength="255" name="emails-0-email_address" type="text">
<span class="help-block">A valid e-mail address.</span>
</div>
</div>
<div class="form-group">
<label for="emails-0-priority_level" class="col-xs-12 col-sm-5 col-md-3 col-lg-3 control-label">
Priority level <span style="color: #a60000;">*</span>
</label>
<div class="col-xs-12 col-sm-7 col-md-9 col-lg-9">
<input class="form-control" id="id_emails-0-priority_level" name="emails-0-priority_level" type="text">
<span class="help-block">An integer used to define a priority level for e-mail addresses of a contact.</span>
</div>
</div>
<div class="form-group">
<label for="emails-0-DELETE" class="col-xs-12 col-sm-5 col-md-3 col-lg-3 control-label">
Delete
</label>
<div class="col-xs-12 col-sm-7 col-md-9 col-lg-9">
<input type="hidden" name="emails-0-DELETE" id="id_emails-0-DELETE">
<span class="help-block"></span>
</div>
</div>
<a class="delete-row" href="javascript:void(0)">remove</a></div><a class="add-row" href="javascript:void(0)">add another</a>
</fieldset>
Anyone has a clue ?
As mentioned here, the problem came from the django-dynamic-form library !
Just in case someone fall into the same trap...