Ensure at least one checkbox is selected - Django Forms - django

I'm using Django's forms functionality to create a signup page. I've three checkboxes (BooleanField's) and I want to implement validations to ensure that the user enters at least one option.
This is the registration template
<div class="form-check form-check-inline">
{{form.is_student}}
<label class="form-check-label" for="inlineRadio1"> &nbsp{{form.is_student.label}}&nbsp</label>
{{form.is_teacher}}
<label class="form-check-label" for="inlineRadio2"> &nbsp{{form.is_teacher.label}}&nbsp</label>
{{form.is_parent}}
<label class="form-check-label" for="inlineRadio3"> &nbsp{{form.is_parent.label}}&nbsp</label>
</div>
This is form.py
class SignUp_Form(forms.ModelForm):
is_student = forms.BooleanField(label='Student', required=False, )
is_teacher = forms.BooleanField(label='Teacher', required=False)
is_parent = forms.BooleanField(label='Parent', required=False)

This is not the right way to do that. I would say to use one of the below methods.
Change the form fields to radio buttons. In this way you can tell the user to select one of the above and mark that field as required=True.
Or the other way is write a js function to check at least one is selected before submission.
I would personally feel to go with the first one as it makes more good way of a programmer.

THe right way to do that is to create a multiple choice required field with three choices.

Related

Django: Switch a form in template depending on choice field

I am looking for a way to switch and display a form in template, depending on choice in CharField in another form.
My app has the following models:
class Damage(models.Model):
damage_place = models.CharField()
damage_date = models.DateField()
class DamageType1(models.Model):
damage = models.ForeignKey(Damage)
...
class DamageType2(models.Model):
damage = models.ForeignKey(Damage)
...
class DamageType3(models.Model):
damage = models.ForeignKey(Damage)
...
Damage model has a DamageForm(forms.ModelForm) that is filled in by another user.
Each DamageType model has different fields (marked as ... for simplicity) and own DamageTypeForm1(forms.ModelForm), DamageTypeForm2(forms.ModelForm) and DamageTypeForm3(forms.ModelForm).
There is also a form in a template specifying which DamageType to choose:
class DamageSpecify(forms.Form):
DAMAGE_CHOICES = [
('DamageType1', 'DamageType1'),
('DamageType2', 'DamageType2'),
('DamageType3', 'DamageType3'),
]
damage_type = forms.CharField(choices=DAMAGE_CHOICES )
And now, after choose specific damage_type in DamageSpecify I would like to display the filled DamageForm and empty DamageType(1, 2 or 3) in template to fill and save both forms.
How could this be done?
How I'd tackle it. Write 4 forms. One, with a single ChoiceField. The other 3, to get the appropriate inputs for damage types 1 to 3 as chosen in the first. Display all the forms in your template:
<form> {% csrf_token %}
{{damage_type_form.as_p}}
<div id="type1">
{{damage_form_1.as_p}}
</div>
<div id="type2">
{{damage_form_2.as_p}}
</div>
<div id="type3">
{{damage_form_3.as_p}}
</div>
<input type="submit" ...>
</form>
(obviously, pass the four forms in your context, as you'd normally pass just one)
In your view POST processing, you will use the damage_type to determine which form is to be validated and used. Bind all four forms (to request.POST), then use the choice to decide which one gets validated and used. Ignore the other two.
(This may be the first time I've actually thought that a Function-based view will probably be easier than using the Class-Based Views)
Finally, write some JS that will hide the <div>s that are not selected in the damage_type pulldown/ ChoiceField.

Django Form add class to div, input field and label

This is the html django form generated for an ImageField
<div id="div_id_image" class="form-group">
<label for="id_image" class=""> Image </label>
<div class=""> <input type="file" name="image" accept="image/*" class="clearablefileinput form-control-file" id="id_image">
</div>
Now, I can write custom html code to customize this field. But, my use-case is just to add 3 classes, one for the outer div, one for the label and one for the input field itself.
Is it possible to add these 3 classes in django form without writing any custom html code
It is possible. use "django-widget-tweaks" tools. It will give you full flexibility in your form.
check out the official documentation:
https://pypi.org/project/django-widget-tweaks/
If you want to add only class name from form.py
(you can try this but code is not tested)
from django import forms
class xyzform(forms.ModelForm):
x= forms.CharField(widget= forms.TextInput
(attrs={'class':'some_class',
'id':'some_id'}))
y= forms.CharField(widget= forms.TextInput
(attrs={'class':'some_class',
'id':'some_id'}))
class Meta:
model = xyzModal
fields = [
'x',
'y'
]

Django - Modify Inlineformset Delete button

I do a custom UI/UX for an inlineformset.
By default the inlineformset widget has a delete button.
I wan to add and remove forms from inlineformset dynamic using javascript.
In some cases the delete is just a button instead of the checkbox, in other cases is in a modal window.
When a user click delete the form is removed from the page with javascript.
So, I try to do this without using the default widget, render fields in the template, but I don't know how to tell Django witch fields to remove and if is necessary to readjust the ids and names of the fields.
My solution for this problem was to just overwrite the template_name of CheckboxInput widget class:
widgets.CheckboxInput.template_name = 'widgets/delete.html'
I added that in my {app}/widgets.py that hosts my custom widgets. As I am using the same format accross my app, I think it's the only way to go.
{app}/templates/widgets/delete.html:
<div class="checkbox checkbox-styled">
<label>
<input name={{ widget.name }} type="checkbox" value="true" {% if widget.attrs.checked == True %}checked{% endif %}>
<span>Delete</span>
</label>
</div>
If it would not have been the inlineformset_factory then the best way was to create a new class extending BaseFormSet and to overwrite the widget in add_fields method like suggested in this answer.

Customising django ImageField markup in template

I have a form which allows you to upload an image, but I want to know if it is possible to customise the markup that Django generates.
In the model it is created as an ImageField:
logo = models.ImageField(blank=True, null=True)
In the template I am creating an 'upload' form field using
{{ form.logo }}
This is the markup that gets generated:
Currently: dog.jpg
<input id="logo-clear_id" name="logo-clear" type="checkbox">
<label for="logo-clear_id">Clear</label>
<br>Change: <input id="id_logo" name="logo" type="file">
I want to know if I can change that markup by drilling down further, so that I can for example nest the checkbox to clear the image within its label. I also would like to use my own markup to separate the option to clear the form field from the option to upload a new one. However, I can't find any documentation on how to do this. I've tried outputting
{{ logo.logo-clear }}
directly but this throws an error.
The solution was to create a custom version of the widget being used in my forms.py: https://docs.djangoproject.com/en/1.10/_modules/django/forms/widgets/#ClearableFileInput
from django.forms.widgets import ClearableFileInput
class CustomImageFieldWidget(ClearableFileInput):
template_with_clear = '<label for="%(clear_checkbox_id)s">%(clear)s %(clear_checkbox_label)s</label>'
class OrganisationProfileForm(OrganisationCreateForm):
class Meta(OrganisationCreateForm.Meta):
widgets = {
'logo': CustomImageFieldWidget,
}

achieve full customisation with django forms

I have a model with the following fields
class Entry(models.Model):
title = models.CharField(max_length=50)
comments = models.TextField()
start = models.DateField()
end = models.DateField()
remind = models.BooleanField()
and a modelform
class EntryForm(models.Model):
class Meta:
model = Entry
I want to render a form using bootstrap 3. I can render the form using the same kind of form e.g all fields horizontal or divide them by three in a row. How about more customization. Like
<label title>
<input title>
<label comments>
<input comments>
<label start> <label end>
<input start> <input end>
<label remind><input remind>
I guess this should be done manually. How can I know to which field of the form i am refering in the template. And by which field i mean is it title, is it comments? Is this correct (suppose the view has passed a form argument to the template) something like
<label for={{form.title.auto_id}}>Title</label>
{{form.title}}
is that correct? Now i can place what ever div's and arrange form fields as I like correct?Is that the right way?
How powerfull can a form of django be?
Here's a thought... Django has extensive, well-written documentation:
https://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template
Instead of guessing random things you could just read the docs.
Additionally there are a number of Django apps designed to simplify outputting form HTML in a Bootstrap style, such as:
https://github.com/dyve/django-bootstrap3 (recommended)
https://github.com/dyve/django-bootstrap-toolkit
https://github.com/tzangms/django-bootstrap-form